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