source: abuse/trunk/src/menu.cpp @ 118

Last change on this file since 118 was 118, checked in by Sam Hocevar, 10 years ago
  • Create a VolumeWindow? class with most of the volume_window stuff and moved it to src/ui/volumewindow.cpp.
File size: 17.1 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *
5 *  This software was released into the Public Domain. As with most public
6 *  domain software, no warranty is made or implied by Crack dot Com or
7 *  Jonathan Clark.
8 */
9
10#include "config.h"
11
12#include <math.h>
13
14#include "dev.hpp"
15
16#include "ui/volumewindow.hpp"
17
18#include "menu.hpp"
19#include "lisp.hpp"
20#include "game.hpp"
21#include "timing.hpp"
22#include "game.hpp"
23#include "id.hpp"
24#include "pmenu.hpp"
25#include "gui.hpp"
26#include "property.hpp"
27#include "clisp.hpp"
28#include "gamma.hpp"
29#include "dprint.hpp"
30#include "demo.hpp"
31#include "loadgame.hpp"
32#include "scroller.hpp"
33#include "netcfg.hpp"
34#include "sock.hpp"
35
36extern net_protocol *prot;
37
38static VolumeWindow *volume_window;
39
40//percent is 0..256
41void tint_area(int x1, int y1, int x2, int y2, int r_to, int g_to, int b_to, int percent)
42{
43  int x,y;
44  short cx1,cy1,cx2,cy2;
45  screen->get_clip(cx1,cy1,cx2,cy2);
46  if (x1<cx1) x1=cx1;
47  if (y1<cy1) y1=cy1;
48  if (x2>cx2) x2=cx2;
49  if (y2>cy2) y2=cy2;
50  if (x2<x1 || y2<y1) return ;
51
52  percent=256-percent;
53
54  screen->lock();
55  for (y=y1;y<=y2;y++)
56  {
57    uint8_t *sl=screen->scan_line(y)+x1;
58    for (x=x1;x<=x2;x++,sl++)
59    {
60      uint8_t *paddr=(uint8_t *)pal->addr()+(*sl)*3;
61      uint8_t r=((*(paddr++))-r_to)*percent/256+r_to;
62      uint8_t g=((*(paddr++))-g_to)*percent/256+g_to;
63      uint8_t b=((*(paddr++))-b_to)*percent/256+b_to;
64      *sl=color_table->lookup_color((r)>>3,(g)>>3,(b)>>3);
65    }
66  }
67  screen->add_dirty(x1,y1,x2,y2); 
68  screen->unlock();
69}
70
71void darken_area(int x1, int y1, int x2, int y2, int amount)
72{
73  int x,y;
74  short cx1,cy1,cx2,cy2;
75  screen->get_clip(cx1,cy1,cx2,cy2);
76  if (x1<cx1) x1=cx1;
77  if (y1<cy1) y1=cy1;
78  if (x2>cx2) x2=cx2;
79  if (y2>cy2) y2=cy2;
80  if (x2<x1 || y2<y1) return ;
81
82  screen->lock();
83  for (y=y1;y<=y2;y++)
84  {
85    uint8_t *sl=screen->scan_line(y)+x1;
86    for (x=x1;x<=x2;x++,sl++)
87    {
88      uint8_t *paddr=(uint8_t *)pal->addr()+(*sl)*3;
89      uint8_t r=(*(paddr++))*amount/256;
90      uint8_t g=(*(paddr++))*amount/256;
91      uint8_t b=(*(paddr++))*amount/256;
92      *sl=color_table->lookup_color((r)>>3,(g)>>3,(b)>>3);
93    }
94  }
95  screen->add_dirty(x1,y1,x2,y2);
96  screen->unlock();
97}
98
99void dark_widget(int x1, int y1, int x2, int y2, int br, int dr, int amount)
100{
101  screen->add_dirty(x1,y1,x2,y2);
102  screen->line(x1,y1,x1,y2,br);
103  screen->line(x1+1,y1,x2,y1,br);
104  screen->line(x2,y1+1,x2,y2,dr);
105  screen->line(x1+1,y2,x2,y2,dr);
106  darken_area(x1+1,y1+1,x2-1,y2-1,amount); 
107}
108
109char *men_str(void *arg)
110{
111  switch (item_type(arg))
112  {
113    case L_STRING :
114    { return lstring_value(arg); } break;
115    case L_CONS_CELL :
116    { return lstring_value(CAR(arg)); } break;
117    default :
118    {
119      lprint(arg);
120      printf(" is not a valid menu option\n");
121      exit(0);
122    }
123  }
124  return NULL;
125}
126
127int menu(void *args, JCFont *font)             // reurns -1 on esc
128{
129  main_menu();
130  char *title=NULL;
131  if (!NILP(CAR(args)))
132    title=lstring_value(CAR(args));
133  Cell *def=lcar(lcdr(lcdr(args)));
134  args=CAR(CDR(args));
135
136  int options=list_length(args);
137  int mh=(font->height()+1)*options+10,maxw=0;
138
139  Cell *c=(Cell *)args;
140  for (;!NILP(c);c=CDR(c))
141  {
142    if( strlen(men_str(CAR(c))) > (unsigned)maxw)
143      maxw = strlen(men_str(CAR(c)));
144  }
145 
146  int mw=(font->width())*maxw+20;
147  int mx=screen->width()/2-mw/2,
148      my=screen->height()/2-mh/2;
149 
150
151  screen->add_dirty(mx,my,mx+mw-1,my+mh-1);
152
153  if (title)
154  {
155    int tl=strlen(title)*font->width();
156    int tx=screen->width()/2-tl/2;
157    dark_widget(tx-2,my-font->height()-4,tx+tl+2,my-2,wm->medium_color(),wm->dark_color(),180);
158    font->put_string(screen,tx+1,my-font->height()-2,title,wm->bright_color());
159  }
160 
161  dark_widget(mx,my,mx+mw-1,my+mh-1,wm->medium_color(),wm->dark_color(),200);
162
163
164  int y=my+5;
165  for (c=(Cell *)args;!NILP(c);c=CDR(c))
166  {
167    char *ms=men_str(CAR(c));
168    font->put_string(screen,mx+10+1,y+1,ms,wm->black());
169    font->put_string(screen,mx+10,y,ms,wm->bright_color());
170    y+=font->height()+1;
171  }
172
173  wm->flush_screen();
174  event ev;
175  int choice=0,done=0;
176  int bh=font->height()+3;
177  image *save=new image(mw-2,bh);
178  int color=128,cdir=50;
179 
180  time_marker *last_color_time=NULL;
181  if (!NILP(def))
182    choice=lnumber_value(def);
183  do
184  {
185    wm->flush_screen();
186    if (wm->event_waiting())
187    {
188      wm->get_event(ev);
189      if (ev.type==EV_KEY)
190      {
191        switch (ev.key)
192        {
193          case JK_ESC :
194          { choice=-1; done=1; } break;
195          case JK_ENTER :
196          { done=1; } break;
197          case JK_DOWN :
198          { if (choice<options-1)
199            choice++;
200          else choice=0;
201          } break;
202          case JK_UP :
203          {
204            if (choice>0)
205            choice--;
206            else choice=options-1;
207          } break;                   
208        }
209      } else if (ev.type==EV_MOUSE_BUTTON && ev.mouse_button)
210      {
211        if (ev.mouse_move.x>mx && ev.mouse_move.x<mx+mw && ev.mouse_move.y>my &&
212            ev.mouse_move.y<my+mh)
213        {
214          int msel=(ev.mouse_move.y-my)/(font->height()+1);
215          if (msel>=options) msel=options-1;
216          if (msel==choice)                    // clicked on already selected item, return it
217            done=1;
218          else choice=msel;                    // selects an item
219        }
220      }
221    }
222
223    time_marker cur_time;
224    if (!last_color_time || (int)(cur_time.diff_time(last_color_time)*1000)>120)
225    {       
226      if (last_color_time)
227        delete last_color_time;
228      last_color_time=new time_marker;
229
230      int by1=(font->height()+1)*choice+my+5-2;
231      int by2=by1+bh-1;
232
233      screen->put_part(save,0,0,mx+1,by1,mx+mw-2,by2);
234      tint_area(mx+1,by1,mx+mw-2,by2,63,63,63,color);
235
236      char *cur=men_str(nth(choice,args));
237      font->put_string(screen,mx+10+1,by1+3,cur,wm->black());
238      font->put_string(screen,mx+10,by1+2,cur,wm->bright_color());
239      screen->rectangle(mx+1,by1,mx+mw-2,by2,wm->bright_color());
240
241      color+=cdir;
242
243      if (color<12 || color>256)
244      {
245        cdir=-cdir;
246        color+=cdir;
247      }
248      wm->flush_screen();
249      save->put_image(screen,mx+1,by1);
250    } else milli_wait(10);
251
252  } while (!done);
253  if (last_color_time)
254    delete last_color_time;
255  delete save;
256  the_game->draw(the_game->state==SCENE_STATE);
257
258  if (choice!=-1)
259  {
260    void *val=nth(choice,args);
261    if (item_type(val)==L_CONS_CELL)   // is there another value that the user want us to return?
262      return lnumber_value(lcdr(val)); 
263  }
264  return choice;
265}
266
267static void create_volume_window()
268{
269    volume_window = new VolumeWindow();
270    volume_window->inm->allow_no_selections();
271    volume_window->inm->clear_current();
272    volume_window->show();
273
274    wm->grab_focus(volume_window);
275    wm->flush_screen();
276
277    while(volume_window)
278    {
279        event ev;
280
281        do
282        {
283            wm->get_event(ev);
284        }
285        while(ev.type == EV_MOUSE_MOVE && wm->event_waiting());
286
287        wm->flush_screen();
288
289        if(ev.type == EV_CLOSE_WINDOW
290                 || (ev.type == EV_KEY && ev.key == JK_ESC))
291        {
292            wm->close_window(volume_window);
293            volume_window = NULL;
294        }
295
296        if(!volume_window)
297            break;
298
299        if(ev.type == EV_MESSAGE)
300        {
301            char const *s;
302
303            switch(ev.message.id)
304            {
305            case ID_SFX_UP:
306                sfx_volume += 16;
307                if(sfx_volume > 127)
308                    sfx_volume = 127;
309                volume_window->draw_sfx_vol();
310                s = "sfx/ambtech1.wav";
311                if(sound_avail & SFX_INITIALIZED)
312                    cash.sfx(cash.reg(s, s, SPEC_EXTERN_SFX, 1))
313                        ->play(sfx_volume);
314                break;
315            case ID_SFX_DOWN:
316                sfx_volume -= 16;
317                if(sfx_volume < 0)
318                    sfx_volume = 0;
319                volume_window->draw_sfx_vol();
320                s = "sfx/ambtech1.wav";
321                if(sound_avail & SFX_INITIALIZED)
322                    cash.sfx(cash.reg(s, s, SPEC_EXTERN_SFX, 1))
323                        ->play(sfx_volume);
324                break;
325
326            case ID_MUSIC_UP:
327                music_volume += 16;
328                if(music_volume > 127)
329                    music_volume = 127;
330                volume_window->draw_music_vol();
331                if(current_song)
332                    current_song->set_volume(music_volume);
333                break;
334            case ID_MUSIC_DOWN:
335                music_volume -= 16;
336                if(music_volume < 0)
337                    music_volume = 0;
338                volume_window->draw_music_vol();
339                if(current_song)
340                    current_song->set_volume(music_volume);
341                break;
342            }
343        }
344    }
345
346    wm->close_window(volume_window);
347}
348
349void save_difficulty()
350{
351  FILE *fp=open_FILE("hardness.lsp","wb");
352  if (!fp)
353    dprintf("Unable to write to file hardness.lsp\n");
354  else
355  {
356    fprintf(fp,"(setf difficulty '");
357    if (DEFINEDP(symbol_value(l_difficulty)))
358    {
359      if (symbol_value(l_difficulty)==l_extreme)
360        fprintf(fp,"extreme)\n");
361      else if (symbol_value(l_difficulty)==l_hard)
362        fprintf(fp,"hard)\n");
363      else if (symbol_value(l_difficulty)==l_easy)
364        fprintf(fp,"easy)\n");
365      else
366        fprintf(fp,"medium)\n");
367    } else
368       fprintf(fp,"medium)\n");
369    fclose(fp);
370  }
371}
372
373void fade_out(int steps);
374void fade_in(image *im, int steps);
375
376
377void show_sell(int abortable)
378{
379  void *ss=make_find_symbol("sell_screens");
380  if (!DEFINEDP(symbol_value(ss)))
381  {
382    int sp=current_space;
383    current_space=PERM_SPACE;
384//    char *prog="((\"art/help.spe\" . \"sell2\")(\"art/help.spe\" . \"sell4\")(\"art/help.spe\" . \"sell3\")(\"art/endgame.spe\" . \"credit\"))";
385//    char *prog="((\"art/endgame.spe\" . \"credit\") (\"art/help.spe\" . \"sell6\"))";
386    char const *prog="((\"art/endgame.spe\" . \"credit\"))";
387    set_symbol_value(ss,compile(prog));
388    current_space=sp;
389  }
390
391  if (DEFINEDP(symbol_value(ss)))
392  {
393    image blank(2,2); blank.clear();
394    wm->set_mouse_shape(blank.copy(),0,0);      // don't show mouse
395
396    ss=symbol_value(ss);
397    int quit=0;
398    while (ss && !quit)
399    {
400      int im=cash.reg_object("art/help.spe",CAR(ss),SPEC_IMAGE,1);
401      fade_in(cash.img(im),16);
402
403      event ev;
404      do
405      { wm->flush_screen();
406        wm->get_event(ev);
407      } while (ev.type!=EV_KEY);
408      if (ev.key==JK_ESC && abortable)
409        quit=1;
410      fade_out(16);
411      ss=CDR(ss);
412    }
413    wm->set_mouse_shape(cash.img(c_normal)->copy(),1,1);
414  }
415}
416
417
418void menu_handler(event &ev, input_manager *inm)
419{
420  switch (ev.type)
421  {
422    case EV_MESSAGE :
423    {
424      switch (ev.message.id)
425      {
426        case ID_LIGHT_OFF :
427        if (!volume_window)
428        {
429          gamma_correct(pal,1);
430        } break;
431        case ID_RETURN :
432        if (!volume_window)
433        {
434          the_game->set_state(RUN_STATE);
435        } break;
436        case ID_START_GAME :
437        if (!volume_window)
438        {       
439          the_game->load_level(level_file);
440          the_game->set_state(RUN_STATE);
441          view *v;
442          for (v=player_list;v;v=v->next)
443            if (v->focus)
444              v->reset_player();
445           
446        } break;
447
448   
449        case ID_LOAD_PLAYER_GAME :
450        if (!volume_window)
451        {
452          int got_level=load_game(0,symbol_str("LOAD"));
453          the_game->reset_keymap();
454          if (got_level)
455          {
456            char name[255];
457            sprintf(name,"%ssave%04d.spe", get_save_filename_prefix(), got_level);
458
459            the_game->load_level(name);
460            the_game->set_state(RUN_STATE);         
461          }
462        } break;
463
464
465        case ID_VOLUME :
466        if (!volume_window)
467        { create_volume_window(); } break;
468
469        case ID_MEDIUM :
470        {
471          set_symbol_value(l_difficulty,l_medium);
472          save_difficulty();
473        } break;
474        case ID_HARD :
475        {
476          set_symbol_value(l_difficulty,l_hard);
477          save_difficulty();
478        } break;
479        case ID_EXTREME :
480        {
481          set_symbol_value(l_difficulty,l_extreme);
482          save_difficulty();
483        } break;
484        case ID_EASY :
485        {
486          set_symbol_value(l_difficulty,l_easy);
487          save_difficulty();
488        } break;
489
490        case ID_NETWORKING :
491        {
492          if (!volume_window)
493          {
494            net_configuration *cfg=new net_configuration;
495            if (cfg->input())
496            {
497              if (main_net_cfg) delete main_net_cfg;
498              main_net_cfg=cfg;
499            } else delete cfg;
500            the_game->draw(0);
501            inm->redraw();
502          }
503        } break;
504                     
505        case ID_SHOW_SELL :
506        if (!volume_window)
507        {
508          show_sell(1);
509          screen->clear();
510          if (title_screen>=0)
511          {
512            image *tit=cash.img(title_screen);
513              tit->put_image(screen,screen->width()/2-tit->width()/2,
514                                              screen->height()/2-tit->height()/2);
515          }
516          inm->redraw();
517          fade_in(NULL,8);
518          wm->flush_screen();
519
520        } break;
521      } break;
522    } break;
523    case EV_CLOSE_WINDOW :
524    {
525      if (ev.window==volume_window)
526      { wm->close_window(volume_window); volume_window=NULL; }
527    } break;
528  }
529}
530
531void *current_demo=NULL;
532
533static ico_button *load_icon(int num, int id, int x, int y, int &h, ifield *next, char const *key)
534{
535  char name[20];
536  char const *base = "newi";
537  int a,b,c;
538  sprintf(name,"%s%04d.pcx",base,num*3+1);
539  a=cash.reg("art/icons.spe",name,SPEC_IMAGE,1);
540
541  sprintf(name,"%s%04d.pcx",base,num*3+2);
542  b=cash.reg("art/icons.spe",name,SPEC_IMAGE,1);
543
544  sprintf(name,"%s%04d.pcx",base,num*3+3);
545  c=cash.reg("art/icons.spe",name,SPEC_IMAGE,1);
546
547  h=cash.img(a)->height();
548
549  return new ico_button(x,y,id,b,b,a,c,next,-1,key);
550}
551
552ico_button *make_default_buttons(int x,int &y, ico_button *append_list)
553{
554  int h;
555  int diff_on;
556
557  if (DEFINEDP(symbol_value(l_difficulty)))
558  {
559    if (symbol_value(l_difficulty)==l_extreme)
560      diff_on=3;
561    else if (symbol_value(l_difficulty)==l_hard)
562      diff_on=2;
563    else if (symbol_value(l_difficulty)==l_easy)
564      diff_on=0;
565    else
566      diff_on=1;
567  } else  diff_on=3;
568
569 
570  ico_button *start=load_icon(0,ID_START_GAME,x,y,h,NULL,"ic_start");                         y+=h;
571
572  ico_switch_button *set=NULL;
573  if (!main_net_cfg || (main_net_cfg->state!=net_configuration::SERVER && main_net_cfg->state!=net_configuration::CLIENT))
574  {
575    set=new ico_switch_button(x,y,ID_NULL,diff_on,
576                                                 load_icon(3,ID_EASY,x,y,h,
577                                                 load_icon(8,ID_MEDIUM,x,y,h,
578                                                 load_icon(9,ID_HARD,x,y,h,
579                                                 load_icon(10,ID_EXTREME,x,y,h,NULL,"ic_extreme"),
580                                                  "ic_hard"),"ic_medium"),"ic_easy"),NULL);         y+=h;
581
582  }
583
584  ico_button *color=load_icon(4,ID_LIGHT_OFF,x,y,h,NULL,"ic_gamma");                          y+=h; 
585  ico_button *volume=load_icon(5,ID_VOLUME,x,y,h,NULL,"ic_volume");                            y+=h;
586  ico_button *sell=NULL;
587
588  if (prot)
589  {
590    sell=load_icon(11,ID_NETWORKING,x,y,h,NULL,"ic_networking");
591    y+=h; 
592  } else
593  {
594    sell=load_icon(2,ID_SHOW_SELL,x,y,h,NULL,"ic_sell");                           
595    y+=h; 
596  }
597  ico_button *quit=load_icon(6,ID_QUIT,x,y,h,NULL,"ic_quit");                                y+=h;
598
599  if (set)
600  {
601    start->next=set;
602    set->next=color;
603  }
604  else start->next=color;
605
606
607  color->next=volume; 
608  if (sell)
609  {
610    volume->next=sell; 
611    sell->next=quit;
612  } else volume->next=quit;
613
614  ico_button *list=append_list;
615
616  if (append_list)
617  {
618    while (append_list->next)
619      append_list=(ico_button *)append_list->next;
620    append_list->next=start;
621  } else list=start;
622 
623  return list; 
624}
625
626
627ico_button *make_conditional_buttons(int x,int &y)
628
629  ico_button *start_list=NULL;
630  int h;
631  if (current_level)       // should we include a return icon?
632  {
633    start_list=load_icon(7,ID_RETURN,x,y,h,NULL,"ic_return");                       y+=h;
634  }
635   
636 
637  ico_button *load;
638  if (show_load_icon())
639  { load= load_icon(1,ID_LOAD_PLAYER_GAME,x,y,h,NULL,"ic_load");                     y+=h;}
640  else load=NULL;
641
642  if (start_list) start_list->next=load;
643  else start_list=load;
644
645  return start_list;   
646}
647
648void main_menu()
649{
650        int y=yres/2-100;
651        ico_button *list=make_conditional_buttons(xres-33,y);
652        list=make_default_buttons(xres-33,y,list);
653
654        input_manager *inm=new input_manager(screen,list);
655        inm->allow_no_selections();
656        inm->clear_current();
657
658        screen->add_dirty(0,0,319,199);
659
660        event ev;
661
662        int stop_menu=0;
663        time_marker start;
664        wm->flush_screen();
665        do
666        {
667                time_marker new_time;
668
669                if (wm->event_waiting())
670                {
671                        do
672                        {
673                                wm->get_event(ev);
674                        } while (ev.type==EV_MOUSE_MOVE && wm->event_waiting());
675                        inm->handle_event(ev,NULL);
676                        if (ev.type==EV_KEY && ev.key==JK_ESC)
677                                wm->push_event(new event(ID_QUIT,NULL));
678
679                        menu_handler(ev,inm);
680                        start.get_time();
681
682                        wm->flush_screen();
683                }
684                else
685                {
686                        // ECS - Added so that main menu doesn't grab 100% of CPU
687                        milli_wait(30);
688                }
689
690                if (new_time.diff_time(&start)>10)
691                {
692                        if (volume_window)
693                                start.get_time();
694                        else
695                        {
696                                if (!current_demo)
697                                {
698                                        void *d=make_find_symbol("demos");
699                                        if (DEFINEDP(symbol_value(d)))
700                                                current_demo=symbol_value(d);
701                                }
702                                if (current_demo)
703                                {
704                                        demo_man.set_state(demo_manager::PLAYING,lstring_value(CAR(current_demo)));
705                                        stop_menu=1;
706                                        current_demo=CDR(current_demo);
707                                }
708                        }
709                }
710
711                if (volume_window) stop_menu=0;  // can't exit with volume window open
712                else if (main_net_cfg && main_net_cfg->restart_state()) stop_menu=1;
713                else if (the_game->state==RUN_STATE) stop_menu=1;
714                else if (ev.type==EV_MESSAGE)
715                {
716                        if (ev.message.id==ID_START_GAME || ev.message.id==ID_RETURN)
717                                stop_menu=1;
718                        else if (ev.message.id==ID_QUIT)
719                        {
720                                if (confirm_quit())
721                                        stop_menu=1;
722                                else
723                                {
724                                        ev.type=EV_SPURIOUS;
725                                        start.get_time();
726                                }
727                        }
728                }
729        } while (!stop_menu);
730
731        delete inm;
732
733        if (ev.type==EV_MESSAGE && ev.message.id==ID_QUIT)   // propogate the quit message
734                the_game->end_session();
735}
736
737
Note: See TracBrowser for help on using the repository browser.