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

Last change on this file since 481 was 481, checked in by Sam Hocevar, 11 years ago

Fuck the history, I'm renaming all .hpp files to .h for my own sanity.

File size: 18.0 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.h"
15
16#include "ui/volumewindow.h"
17
18#include "menu.h"
19#include "lisp.h"
20#include "game.h"
21#include "timing.h"
22#include "game.h"
23#include "id.h"
24#include "pmenu.h"
25#include "gui.h"
26#include "property.h"
27#include "clisp.h"
28#include "gamma.h"
29#include "dprint.h"
30#include "demo.h"
31#include "loadgame.h"
32#include "scroller.h"
33#include "netcfg.h"
34#include "sock.h"
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                    cache.sfx(cache.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                    cache.sfx(cache.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=cache.reg_object("art/help.spe",CAR(ss),SPEC_IMAGE,1);
401      fade_in(cache.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(cache.img(c_normal)->copy(),1,1);
414  }
415}
416
417
418void menu_handler(event &ev, InputManager *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=cache.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=cache.reg("art/icons.spe",name,SPEC_IMAGE,1);
540
541  sprintf(name,"%s%04d.pcx",base,num*3+2);
542  b=cache.reg("art/icons.spe",name,SPEC_IMAGE,1);
543
544  sprintf(name,"%s%04d.pcx",base,num*3+3);
545  c=cache.reg("art/icons.spe",name,SPEC_IMAGE,1);
546
547  h=cache.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    InputManager *inm=new InputManager(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.