1 /*
2     shop.cpp - implements the shop function, which lets you buy nifty equipment
3                 (and badly needs cleaning up)
4     Copyright (C) 2006,2008 Mark boyd
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be fun to play,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20 
21 #include "game.h"
22 #include "etc.h"
23 #include "text.h"
24 #include "shop.h"
25 #include "weapons.h"
26 
27 //Positions of various UI elements in the shop.
28 namespace pos
29 {
30   const int btn_width=100, btn_height=20; //standard button size
31   const int connector_gap=20; //width of the gap between dep. buttons and object buttons.
32   const int top_margin=30;    //Gap between top of rect and highest button
33   const int bottom_margin=5;
34   const int right_margin=5;
35   const int left_margin=5;
36   const int btn_ygap=5;       //Vertical gap between buttons
37   const int btn_xgap=5;
38 
39   //TODO: this should depend on how much screen height we've got to work with
40   const int max_visible_obj_btns=10; //If there are more than this, scrolling happens.
41 
42   SDL_Rect big_rect;  //Rect which the shop is allowed to draw in.  All other
43                       //values are derived from this (and the constants).
44 
45 
46   SDL_Rect left_panel;
47   SDL_Rect right_panel;
48 
49   int obj_btn_left, obj_btn_right, obj_btn1_top;
50   int obj_btn_scroll_top;
51 
52   int dep_btn_left, dep_btn_right, dep_btn1_top;
53   int connector_x;
54 
55   SDL_Rect prev_rect, next_rect;
56   std::vector<SDL_Rect> scroll_rects;
57   std::vector<SDL_Rect> obj_rects; //use these of there is no scrolling
58 
59   int square; //scale factor for the big ship picture.
60 
61   int bottom_margin_y;  //y coord of the top of the bottom margin
62   int right_margin_x;
63 
64   int desc_x, desc_y;
65 
init(SDL_Rect * _big_rect)66   void init(SDL_Rect *_big_rect)
67   {
68     big_rect=*_big_rect;
69 
70     left_panel=big_rect; left_panel.w=left_panel.w*2/3;
71     right_panel=big_rect; right_panel.x=left_panel.x+left_panel.w; right_panel.w=big_rect.w-left_panel.w;
72 
73     obj_btn_left=right_panel.x;
74     obj_btn_right=obj_btn_left+btn_width;
75     obj_btn_scroll_top = top_margin+btn_height;
76 
77     dep_btn_left=right_panel.x-btn_width-connector_gap;
78     dep_btn_right=dep_btn_left+btn_width;
79 
80     obj_btn1_top=dep_btn1_top=big_rect.y+top_margin;
81     connector_x=(dep_btn_left+btn_width+obj_btn_left)/2;
82 
83     //scroll rects
84     {
85     scroll_rects.clear();
86     int w_left=pos::obj_btn_left;
87     int w_top=pos::obj_btn_scroll_top;
88     int w_gap=pos::btn_ygap;
89     int w_height=pos::btn_height;
90     int w_width=pos::btn_width;
91 
92     for(int i=0; i<pos::max_visible_obj_btns-3; ++i) //-3 to make room for "prev" and "next" buttons.
93     {
94       SDL_Rect r={w_left,w_top+i*(w_height+w_gap), w_width, w_height};
95       scroll_rects.push_back(r);
96     }
97 
98     SDL_Rect rp={w_left,w_top-(w_height+w_gap)*3/2, w_width, w_height};
99     prev_rect=rp;
100 
101     SDL_Rect rn={w_left,w_top+(w_height+w_gap)*(2*pos::max_visible_obj_btns-5)/2, w_width, w_height};
102     next_rect=rn;
103     }
104 
105     //obj rects
106     {
107       obj_rects.clear();
108 
109       int w_left=pos::obj_btn_left;
110       int w_top=pos::obj_btn1_top;
111       int w_gap=pos::btn_ygap;
112       int w_height=pos::btn_height;
113       int w_width=pos::btn_width;
114 
115       for(int i=0; i<pos::max_visible_obj_btns; ++i)
116       {
117         SDL_Rect r={w_left,w_top+i*(w_height+w_gap), w_width, w_height};
118         obj_rects.push_back(r);
119       }
120     }
121 
122     SDL_Surface *ship_bmp=game::the_game->m_bmp_pool.get_bitmap("ship.png");
123     square=std::min(pos::left_panel.w, pos::left_panel.h)*8/(10*std::max(ship_bmp->w, ship_bmp->h));
124 
125     bottom_margin_y=big_rect.y+big_rect.h-bottom_margin;
126     right_margin_x = big_rect.x+big_rect.w-right_margin;
127 
128     desc_x=left_panel.x+left_panel.w*9/10;
129     desc_y=right_panel.y+right_panel.h*2/3;
130   }
131 }
132 
point_in_rect(int x,int y,SDL_Rect rect)133 bool point_in_rect(int x, int y, SDL_Rect rect)
134 {
135   return (rect.x<x && x<rect.x+rect.w && rect.y<y && y< rect.y+rect.h);
136 }
137 
138 
139 namespace
140 {
141 
142   //the shop is in fact a department store :)
143   enum department_id
144   {
145     D_WEAPONS,
146     D_SYSTEMS,
147     D_ENGINE,
148   };
149 
150   department_id cur_department;
151   int mount_width, mount_height;
152 }
153 
draw_button(SDL_Surface * surface,const std::string & text,SDL_Rect & rect,Uint32 colour)154 void draw_button(SDL_Surface *surface, const std::string &text, SDL_Rect &rect, Uint32 colour)
155 {
156   Uint32 white=SDL_MapRGB(surface->format, 255,255,255);
157 
158   SDL_FillRect(surface, &rect, colour);
159   text::draw_centre(text, surface, rect.x+rect.w/2, rect.y+rect.h/2, white);
160 }
161 
162 
163 
164 
165 class department
166 {
167 public:
department(int num_objects,SDL_Rect * button_rect)168   department(int num_objects, SDL_Rect *button_rect)
169   {
170     m_num_objects=num_objects;
171     m_scroll=0;
172     m_selected=-1;
173     m_button_rect=button_rect;
174   }
175 
draw_stuff()176   virtual void draw_stuff(){};
177 
178   void draw_obj_buttons(SDL_Surface *surface);
179   void handle_click(int x, int y);
180 
~department()181   virtual ~department(){} //Not really needed, shuts compiler up.
182 
183 
184 private:
vhandle_click(int x,int y)185   virtual void vhandle_click(int x,int y){};
186   virtual std::string name(int)=0;
187 
188   int m_scroll;
189   SDL_Rect *m_button_rect;
190 
191 protected:
192   int m_num_objects;
193   int m_selected;
194 };
195 
draw_obj_buttons(SDL_Surface * surface)196 void department::draw_obj_buttons(SDL_Surface *surface)
197 {
198   Uint32 button_col    =SDL_MapRGB(surface->format,  32, 32,64);
199   Uint32 button_sel_col=SDL_MapRGB(surface->format,  64, 64,128);
200   Uint32 white=SDL_MapRGB(surface->format, 255,255,255);
201 
202   if (m_num_objects > pos::max_visible_obj_btns)
203   {
204     //Draw with scrolling.
205     for(int i=0; i<pos::scroll_rects.size(); ++i)
206     {
207       SDL_Rect r = pos::scroll_rects[i];
208       SDL_FillRect(surface, &r, (i+m_scroll==m_selected)?button_sel_col:button_col);
209       text::draw_centre(name(i+m_scroll), surface, r.x+r.w/2, r.y+r.h/2, white);
210 
211       int y=r.y+r.h/2;
212       SDL_Rect r2={pos::connector_x,y-1, r.x-pos::connector_x, 2};
213       SDL_FillRect(surface, &r2, button_col);
214     }
215 
216     {
217           int connector_y=m_button_rect->y+pos::btn_height/2;
218           int top=std::min(pos::scroll_rects[0].y+pos::scroll_rects[0].h/2, connector_y);
219           int bottom=std::max(pos::scroll_rects.back().y+pos::scroll_rects.back().h/2, connector_y);
220           SDL_Rect r_conn={pos::connector_x-1, top, 2, bottom-top};
221           SDL_FillRect(surface, &r_conn, button_col);
222     }
223 
224     //prev/next buttons
225     draw_button(surface, "Prev", pos::prev_rect, button_col);
226     draw_button(surface, "Next", pos::next_rect, button_col);
227   }
228   else
229   {
230 
231     //simple case: draw normally
232     for(int i=0; i<m_num_objects; ++i)
233     {
234       SDL_Rect r = pos::obj_rects[i];
235       SDL_FillRect(surface, &r, (i==m_selected)?button_sel_col:button_col);
236       text::draw_centre(name(i), surface, r.x+r.w/2, r.y+r.h/2, white);
237 
238       int y=r.y+r.h/2;
239       SDL_Rect r2={pos::connector_x,y-1, r.x-pos::connector_x, 2};
240       SDL_FillRect(surface, &r2, button_col);
241     }
242 
243     if (m_num_objects)
244     {
245       int connector_y=m_button_rect->y+pos::btn_height/2;
246       int top=std::min(pos::obj_rects[0].y+pos::btn_height/2, connector_y);
247       int bottom=std::max(pos::obj_rects[m_num_objects-1].y+pos::btn_height/2, connector_y);
248       SDL_Rect r_conn={pos::connector_x-1, top, 2, bottom-top};
249       SDL_FillRect(surface, &r_conn, button_col);
250     }
251 
252   }
253 }
254 
handle_click(int click_x,int click_y)255 void department::handle_click(int click_x, int click_y)
256 {
257   if (m_num_objects > pos::max_visible_obj_btns)
258   {
259     for(int i=0; i<pos::scroll_rects.size(); ++i)
260       if(point_in_rect(click_x, click_y, pos::scroll_rects[i]))
261       {
262         m_selected=i+m_scroll;
263       }
264 
265     //next/prev?
266     if(point_in_rect(click_x, click_y, pos::prev_rect))
267     {
268       m_scroll=std::max(0, m_scroll-1);
269     }
270     if(point_in_rect(click_x, click_y,pos::next_rect))
271     {
272       m_scroll=std::min<int>(m_num_objects-(pos::max_visible_obj_btns-3), m_scroll+1);
273     }
274   }
275   else
276   {
277     for(int i=0; i<m_num_objects; ++i)
278       if(point_in_rect(click_x, click_y, pos::obj_rects[i]))
279       {
280         m_selected=i;
281       }
282   }
283 
284   vhandle_click(click_x, click_y);
285 }
286 
287 //The departments hold whatever is different about different equipment types
288 //(common stuff goes in department)
289 class weapons_dpt:public department
290 {
291 public:
weapons_dpt(SDL_Rect * br)292   weapons_dpt(SDL_Rect *br):department(weapon_types().size(),br)
293   {
294     m_selected_mount=-1;
295   }
296 
name(int i)297   std::string name(int i){return weapon_types()[i].name;}
298 
299 
draw_stuff(SDL_Surface * surface)300   void draw_stuff(SDL_Surface* surface)
301   {
302     Uint32 white=SDL_MapRGB(surface->format, 255,255,255);
303 
304     //draw weapon mounts
305     const int x_centre=pos::left_panel.x+pos::left_panel.w/2;
306     const int y_centre=pos::left_panel.y+pos::left_panel.h/2;
307 
308     SDL_Surface *mount_bmp=game::the_game->m_bmp_pool.get_bitmap("weapon_point.png");
309     mount_width=mount_bmp->w; mount_height=mount_bmp->h;
310     int rot_size=3*(mount_bmp->w+mount_bmp->h)/2;
311     if (rot_size%2)rot_size++;
312     for (int i=0; i<game::the_game->m_weapon_mounts.size(); ++i)
313     {
314           const weapon_mount &m=game::the_game->m_weapon_mounts[i];
315 
316           //rotate the mount bitmap into a new bitmap;
317           SDL_Surface *rotated;
318           rotated=create_surface(rot_size, rot_size);
319           rotate(mount_bmp, rotated, m.angle);
320 
321 
322           SDL_Rect from={0,0, rotated->w,rotated->h};
323           SDL_Rect to={int(x_centre+m.loc_x*pos::square-rotated->w/2),
324                       int(y_centre+m.loc_y*pos::square-rotated->h/2),
325                       rotated->w,rotated->h};
326           SDL_BlitSurface(rotated, &from, surface, &to);
327 
328           SDL_FreeSurface(rotated);
329 
330           if (weapon_types()[m.type].shop_graphic)
331           {
332             SDL_Surface *weapon_bmp=game::the_game->m_bmp_pool.get_bitmap(weapon_types()[m.type].shop_graphic);
333 
334             rot_size=3*(weapon_bmp->w+weapon_bmp->h)/2;
335             if (rot_size%2)rot_size++;
336 
337             rotated=create_surface(rot_size, rot_size);
338             rotate(weapon_bmp, rotated, m.angle);
339             SDL_Rect from={0,0, rotated->w,rotated->h};
340             SDL_Rect to={int(x_centre+m.loc_x*pos::square-rotated->w/2),
341                         int(y_centre+m.loc_y*pos::square-rotated->h/2),
342                         rotated->w,rotated->h};
343             SDL_BlitSurface(rotated, &from, surface, &to);
344 
345             SDL_FreeSurface(rotated);
346 
347           }
348     }
349 
350         //Generic statussy things
351         if (m_selected_mount>=0 && m_selected_mount < game::the_game->m_weapon_mounts.size())
352         {
353           const weapon_mount &wm=game::the_game->m_weapon_mounts[m_selected_mount];
354           text::draw(std::string("Selected Mount: ")+wm.name+" ("+weapon_types()[wm.type].name+")",
355                     surface, pos::left_margin, pos::bottom_margin_y-10, white);
356           //todo: highlight selected mount?
357         }
358 
359         //TODO: nasty magic numbers!!
360         if (m_selected >=0 && m_selected < weapon_types().size())
361         {
362           int x=pos::desc_x;
363           int y=pos::desc_y;
364           const weapon_type &wt=weapon_types()[m_selected];
365           text::draw(std::string("Selected Weapon: ")+wt.name, surface, x,y, white);
366           y+=20;
367           text::draw(wt.description, surface, x, y, white);
368           y+=15;
369           text::draw("Cost:        "+int2str(wt.cost), surface, x, y, white);
370           y+=15;
371           text::draw("Damage:      "+int2str(wt.damage), surface, x, y, white);
372           y+=15;
373           text::draw("Reload Time: "+int2str(wt.reload), surface, x, y, white);
374           y+=15;
375           text::draw("Recoil     : "+int2str(int(wt.recoil*100)), surface, x, y, white);
376           y+=15;
377           text::draw("Mass     : "+int2str(wt.mass), surface, x, y, white);
378         }
379 
380   }
381 
handle_buy()382   void handle_buy()
383   {
384 
385 
386     if (m_selected_mount>=0 && m_selected_mount < game::the_game->m_weapon_mounts.size())
387     {
388       //This works in all cases because WT_NOTHING has a cost of 0.
389       int trade_cost = weapon_types()[m_selected].cost -
390           weapon_types()[game::the_game->m_weapon_mounts[m_selected_mount].type].cost;
391 
392       if(m_selected >=0 && m_selected < weapon_types().size()
393           && game::the_game->m_player_status.money >= trade_cost)
394       {
395         game::the_game->m_player_status.money -=  trade_cost;
396         game::the_game->m_weapon_mounts[m_selected_mount].type = weapon_id(m_selected);
397       }
398     }
399   }
400 
handle_sell()401   void handle_sell()
402   {
403     if(m_selected_mount>=0 && m_selected_mount < game::the_game->m_weapon_mounts.size())
404     {
405       game::the_game->m_player_status.money +=  weapon_types()[game::the_game->m_weapon_mounts[m_selected_mount].type].cost;
406       game::the_game->m_weapon_mounts[m_selected_mount].type = WT_NOTHING;
407     }
408   }
409 
vhandle_click(int click_x,int click_y)410   void vhandle_click(int click_x, int click_y)
411   {
412     //todo: unduplicate these two
413     const int x_centre=pos::left_panel.x+pos::left_panel.w/2;
414     const int y_centre=pos::left_panel.y+pos::left_panel.h/2;
415 
416         //clicked on weapon mount?
417         for (int i=0; i<game::the_game->m_weapon_mounts.size(); ++i)
418         {
419           const weapon_mount &m=game::the_game->m_weapon_mounts[i];
420           float rel_x=click_x-(x_centre+m.loc_x*pos::square);
421           float rel_y=click_y-(y_centre+m.loc_y*pos::square);
422           float rot_x=1.0*rel_x*cos(-m.angle) - 1.0*rel_y*sin(-m.angle);
423           float rot_y=1.0*rel_x*sin(-m.angle) - 1.0*rel_y*cos(-m.angle);
424           if (-mount_width/2  < rot_x && rot_x < mount_width/2 &&
425               -mount_height/2 < rot_y && rot_y < mount_height/2)
426           {
427             m_selected_mount=i;
428           }
429         }
430   }
431 
432 private:
433   int m_selected_mount;
434 };
435 
436 class engines_dpt:public department
437 {
438 public:
engines_dpt(SDL_Rect * br)439   engines_dpt(SDL_Rect *br):department(engine_types().size(),br){}
name(int i)440   std::string name(int i){return engine_types()[i].name;}
441 
draw_stuff(SDL_Surface * surface)442   void draw_stuff(SDL_Surface *surface)
443   {
444     Uint32 white=SDL_MapRGB(surface->format, 255,255,255);
445     const float gravity = game::the_game->m_arena->gravity();
446     const engine_type &et = engine_types()[game::the_game->m_engine];
447 
448     //TODO: unduplicate x_centre, y_centre
449     const int x_centre=pos::left_panel.x+pos::left_panel.w/2;
450     const int y_centre=pos::left_panel.y+pos::left_panel.h/2;
451     int x=x_centre-100;
452     int y=y_centre-100;
453     int y_gap=15;
454 
455     text::draw(std::string("Current Engine: ")+et.name, surface, x,y, white);
456     y+=y_gap;
457     text::draw(std::string("Thrust: ")+int2str(int(et.thrust)), surface,x,y,white);
458     y+=y_gap;
459     text::draw(std::string("Weight(normal/loaded): ")+int2str(int(gravity*calc_ship_mass()))+
460                         "/"+int2str(int(gravity*(calc_ship_mass()+ball_mass))), surface,x,y,white);
461     y+=2*y_gap;
462     text::draw(std::string("Ship Mass: ")+int2str(calc_ship_mass()), surface,x,y,white);
463     y+=2*y_gap;
464     text::draw(std::string("Ship Acceleration: ")+int2str(int(et.thrust/calc_ship_mass())), surface,x,y,white);
465 
466 
467 
468     if (m_selected>=0 && m_selected < m_num_objects)
469     {
470           const engine_type &eng=engine_types()[m_selected];
471           int x=pos::left_panel.x+pos::left_panel.w*9/10;
472           int y=pos::right_panel.y+pos::right_panel.h*2/3;
473           int y_gap=15;
474 
475           text::draw(std::string("Selected Engine: ")+eng.name, surface, x,y, white);
476           y+=2*y_gap;
477           text::draw(eng.description, surface, x, y, white);
478           y+=y_gap;
479           text::draw("Cost:        "+int2str(eng.cost), surface, x, y, white);
480           y+=y_gap;
481           text::draw("Thrust:      "+int2str(int(eng.thrust*100)), surface, x, y, white);
482           y+=y_gap;
483           text::draw("Mass:        "+int2str(eng.mass), surface, x, y, white);
484           y+=y_gap;
485     }
486   }
487 
handle_buy()488   void handle_buy()
489   {
490     if(m_selected>=0 && m_selected<m_num_objects
491        && game::the_game->m_player_status.money >= engine_types()[m_selected].cost)
492     {
493       game::the_game->m_player_status.money +=  engine_types()[game::the_game->m_engine].cost;
494       game::the_game->m_player_status.money -=  engine_types()[m_selected].cost;
495       game::the_game->m_engine = engine_id(m_selected);
496     }
497   }
498 };
499 
500 class systems_dpt:public department
501 {
502 public:
systems_dpt(SDL_Rect * br)503   systems_dpt(SDL_Rect *br):department(system_types().size(),br)
504   {
505     m_selected_slot=-1;
506 
507     m_mount_bmp=game::the_game->m_bmp_pool.get_bitmap("s_system_mount.png");
508     for(int i=0; i<system_slots; ++i)
509     {
510       int gap=2;
511       int x_centre=pos::left_panel.x+pos::left_panel.w/2;
512       int y_centre=pos::left_panel.y+pos::left_panel.h/2;
513       int x=x_centre+int( (1.0*(i%4)-1.5)*(m_mount_bmp->w+2*gap)-m_mount_bmp->w/2 );
514       int y=y_centre+int( (i/4-2)*(m_mount_bmp->h+2*gap)-m_mount_bmp->h/2 );
515       SDL_Rect r={x,y,m_mount_bmp->w,m_mount_bmp->h};
516       m_mount_rects.push_back(r);
517     }
518   }
519 
name(int i)520   std::string name(int i){return system_types()[i].name;}
521 
draw_stuff(SDL_Surface * surface)522   void draw_stuff(SDL_Surface *surface)
523   {
524         Uint32 button_col    =SDL_MapRGB(surface->format,  32, 32,64);
525         Uint32 white=SDL_MapRGB(surface->format, 255,255,255);
526 
527         //system mounts
528         for(int i=0; i<m_mount_rects.size(); ++i)
529         {
530           if (i==m_selected_slot)
531           {
532             SDL_FillRect(surface, &(m_mount_rects[i]), button_col);
533           }
534 
535           SDL_Rect from={0,0,m_mount_rects[i].w, m_mount_rects[i].h};
536           SDL_BlitSurface(m_mount_bmp, &from, surface, &(m_mount_rects[i]));
537 
538           if (system_types()[game::the_game->m_systems[i]].shop_graphic)
539           {
540             SDL_Surface *bmp=game::the_game->m_bmp_pool.get_bitmap(system_types()[game::the_game->m_systems[i]].shop_graphic);
541             SDL_Rect src={0,0,bmp->w, bmp->h};
542             SDL_Rect dest={m_mount_rects[i].x+(m_mount_rects[i].w-bmp->w)/2,
543                            m_mount_rects[i].y+(m_mount_rects[i].h-bmp->h)/2, bmp->w, bmp->h};
544             SDL_BlitSurface(bmp, &src, surface, &dest);
545           }
546         }
547 
548 
549         //Current system
550         //TODO: move constants into pos!
551         if(m_selected>=0 && m_selected<m_num_objects)
552         {
553           const system_type &st=system_types()[m_selected];
554           int x=pos::desc_x;
555           int y=pos::desc_y;
556           int y_gap=15;
557 
558           text::draw(std::string("Selected System: ")+st.name, surface, x,y, white);
559           y+=2*y_gap;
560           text::draw(st.description, surface, x, y, white);
561           y+=y_gap;
562           text::draw("Cost:  "+int2str(st.cost), surface, x, y, white);
563           y+=y_gap;
564           text::draw("Mass:  "+int2str(st.mass), surface, x, y, white);
565           y+=y_gap;
566         }
567   }
568 
vhandle_click(int x,int y)569   void vhandle_click(int x, int y)
570   {
571     for(int i=0; i<m_mount_rects.size(); ++i)
572       if(point_in_rect(x, y, m_mount_rects[i]))
573       {
574         m_selected_slot=i;
575       }
576   }
577 
handle_buy()578   void handle_buy()
579   {
580     if(m_selected_slot>=0 && m_selected_slot < system_slots
581        && m_selected>=0 && m_selected < m_num_objects
582        && game::the_game->m_player_status.money >= system_types()[m_selected].cost)
583         {
584           game::the_game->m_player_status.money +=  system_types()[game::the_game->m_systems[m_selected_slot]].cost; //autosell existing item
585           game::the_game->m_player_status.money -=  system_types()[m_selected].cost;
586           game::the_game->m_systems[m_selected_slot]=system_id(m_selected);
587         }
588   }
589 
handle_sell()590   void handle_sell()
591   {
592     if(m_selected_slot>=0 && m_selected_slot < system_slots)
593     {
594       game::the_game->m_player_status.money +=  system_types()[game::the_game->m_systems[m_selected_slot]].cost;
595       game::the_game->game::the_game->m_systems[m_selected_slot] = ST_EMPTY;
596     }
597   }
598 
599 private:
600   int m_selected_slot;
601   std::vector<SDL_Rect> m_mount_rects;
602   SDL_Surface *m_mount_bmp;
603 };
604 
605 
606 
607 
608 
609 
610 
611 //Draw ship, centred at coords, scaled by "square"
draw_ship_background(SDL_Surface * screen,int x_centre,int y_centre,int square)612 void draw_ship_background(SDL_Surface *screen, int x_centre, int y_centre, int square)
613 {
614   Uint32 black=SDL_MapRGB(screen->format, 0,0,0);
615   SDL_Surface *ship_bmp=game::the_game->m_bmp_pool.get_bitmap("ship.png");
616   SDL_Surface *tile=create_surface(square,square);
617 
618   const int left=x_centre-(square*ship_bmp->w)/2;
619   const int top =y_centre-(square*ship_bmp->h)/2;
620 
621   SDL_Rect from={0,0,square,square};
622   SDL_Rect to=from;
623   SDL_FillRect(screen, 0, black);
624   SDL_LockSurface(ship_bmp);
625   for(int x=0; x<ship_bmp->w; ++x)
626     for(int y=0; y<ship_bmp->h; ++y)
627     {
628       Uint8 r,g,b,a;
629       SDL_GetRGBA(getpixel(ship_bmp, x, y), ship_bmp->format, &r,&g,&b,&a);
630       float darken=0.4;
631       r=int(darken*r);g=int(darken*g);b=int(darken*b);
632       SDL_FillRect(tile, 0, SDL_MapRGBA(tile->format, r, g, b, a));
633       SDL_UpdateRect(tile,0,0,0,0);
634       to.x=left+x*square; to.y=top+y*square;
635       SDL_BlitSurface(tile, &from, screen, &to);
636     }
637   SDL_UnlockSurface(ship_bmp);
638 
639   SDL_FreeSurface(tile);
640 }
641 
642 
643 
644 
645 
646 
647 
648 
649 //Here's the main shop function.
shop(SDL_Surface * screen,SDL_Rect * draw_rect)650 void shop(SDL_Surface *screen, SDL_Rect *draw_rect)
651 {
652   SDL_ShowCursor(SDL_ENABLE);
653 
654   //initialise stuff
655   cur_department = D_WEAPONS;
656 
657   Uint32 black=SDL_MapRGB(screen->format, 0,0,0);
658   Uint32 button_col    =SDL_MapRGB(screen->format,  32, 32,64);
659   Uint32 button_sel_col=SDL_MapRGB(screen->format,  64, 64,128);
660 
661   pos::init(draw_rect);
662 
663   //centre of left_panel
664   const int x_centre=(pos::left_panel.x+pos::left_panel.w)/2;
665   const int y_centre=(pos::left_panel.y+pos::left_panel.h)/2;
666 
667   const int btn_sep=pos::btn_height+pos::btn_ygap;
668   SDL_Rect weapons_btn={pos::dep_btn_left,pos::dep_btn1_top          , pos::btn_width,pos::btn_height};
669   SDL_Rect systems_btn={pos::dep_btn_left,pos::dep_btn1_top+btn_sep  , pos::btn_width,pos::btn_height};
670   SDL_Rect engine_btn ={pos::dep_btn_left,pos::dep_btn1_top+2*btn_sep, pos::btn_width,pos::btn_height};
671 
672   SDL_Rect buy,sell,exit;
673   {
674     int y=pos::bottom_margin_y-pos::btn_height,  w=pos::btn_width/2,  h=pos::btn_height;
675     SDL_Rect b ={pos::right_margin_x-3*(w+pos::btn_xgap), y,w,h}; buy=b;
676     SDL_Rect s ={pos::right_margin_x-2*(w+pos::btn_xgap), y,w,h}; sell=s;
677     SDL_Rect e ={pos::right_margin_x-1*(w+pos::btn_xgap), y,w,h}; exit=e;
678   }
679 
680 
681   weapons_dpt weapons(&weapons_btn);
682   engines_dpt engines(&engine_btn);
683   systems_dpt systems(&systems_btn);
684 
685 
686   //main loop
687   const int frame=40;
688   bool abort=false;
689   do
690   {
691 
692       bool click=false;
693       int click_x=0, click_y=0;
694       int time=SDL_GetTicks();
695 
696       //Get input
697       SDL_Event event;
698       while (SDL_PollEvent(&event))
699       {
700         if (event.type==SDL_KEYDOWN)
701         {
702           if (event.key.keysym.sym==SDLK_ESCAPE) abort=true;;
703         }
704         else if (event.type==SDL_MOUSEBUTTONDOWN)
705         {
706           click=true;
707           click_x=event.button.x;
708           click_y=event.button.y;
709         }
710         if (event.type==SDL_KEYUP) //todo: unduplicate this!
711         {
712           if (event.key.keysym.sym==SDLK_UP) game::the_game->m_key_flags.up=false;
713           if (event.key.keysym.sym==SDLK_LEFT) game::the_game->m_key_flags.left=false;
714           if (event.key.keysym.sym==SDLK_RIGHT) game::the_game->m_key_flags.right=false;
715           if (event.key.keysym.sym==SDLK_z) game::the_game->m_key_flags.tractor=false;
716           if (event.key.keysym.sym==SDLK_SPACE) game::the_game->m_key_flags.fire=false;
717         }
718       }
719 
720 
721 
722     //Draw stuff...
723     draw_ship_background(screen, x_centre, y_centre, pos::square);
724 
725     //shop department buttons
726     draw_button(screen, "Weapons", weapons_btn, (cur_department==D_WEAPONS)?button_sel_col:button_col);
727     draw_button(screen, "Systems", systems_btn, (cur_department==D_SYSTEMS)?button_sel_col:button_col);
728     draw_button(screen, "Engine", engine_btn,   (cur_department==D_ENGINE)?button_sel_col:button_col);
729     {
730       int connector_y=(cur_department==D_WEAPONS)?(weapons_btn.y+weapons_btn.h/2):
731                       (cur_department==D_SYSTEMS)?(systems_btn.y+systems_btn.h/2):
732                                                   (engine_btn.y+engine_btn.h/2);
733       SDL_Rect r={pos::dep_btn_right, connector_y-1, pos::connector_gap/2, 2};
734       SDL_FillRect(screen, &r, button_col);
735     }
736 
737     switch(cur_department)
738     {
739     case D_WEAPONS:
740       weapons.draw_stuff(screen);
741       weapons.draw_obj_buttons(screen);
742       break;
743 
744       case D_ENGINE:
745         engines.draw_stuff(screen);
746         engines.draw_obj_buttons(screen);
747         break;
748 
749       case D_SYSTEMS:
750         systems.draw_stuff(screen);
751         systems.draw_obj_buttons(screen);
752         break;
753     }
754 
755     //buy/sell/exit butons
756     draw_button(screen, "Buy",  buy, button_col);
757     draw_button(screen, "Sell", sell, button_col);
758     draw_button(screen, "Exit", exit, button_col);
759 
760 
761     if (click)
762     {
763       if (point_in_rect(click_x, click_y, weapons_btn)) cur_department=D_WEAPONS;
764       if (point_in_rect(click_x, click_y, systems_btn)) cur_department=D_SYSTEMS;
765       if (point_in_rect(click_x, click_y, engine_btn)) cur_department=D_ENGINE;
766 
767       switch(cur_department)
768       {
769       case D_WEAPONS:
770         weapons.handle_click(click_x, click_y);
771         if (point_in_rect(click_x, click_y, buy))
772           weapons.handle_buy();
773 
774         if (point_in_rect(click_x, click_y, sell))
775           weapons.handle_sell();
776 
777         break;
778 
779       case D_SYSTEMS:
780         systems.handle_click(click_x, click_y);
781 
782         if (point_in_rect(click_x, click_y, buy))
783           systems.handle_buy();
784 
785         if (point_in_rect(click_x, click_y, sell))
786           systems.handle_sell();
787 
788         //stuff may need updating
789         game::the_game->m_player_status.max_energy=calc_ship_battery();
790         break;
791 
792       case D_ENGINE:
793         engines.handle_click(click_x, click_y);
794 
795         if (point_in_rect(click_x, click_y, buy))
796           engines.handle_buy();
797 
798         break;
799       }
800 
801     if (point_in_rect(click_x, click_y, exit)) abort=true;
802     }
803 
804 
805     update_player_status(screen);
806     SDL_UpdateRect(screen,0,0,0,0);
807 
808     SDL_Delay(std::max<int>(0, time+frame-SDL_GetTicks()));
809 
810   }while(!abort);
811   //End of main loop
812 
813 
814   game::the_game->m_player_status.in_shop=false;
815   SDL_ShowCursor(SDL_DISABLE);
816 
817   //clear screen
818   SDL_FillRect(screen, 0, black);
819   SDL_UpdateRect(screen, 0,0,0,0);
820 }
821 
822 
823