#include "menu.hpp" #include "lisp.hpp" #include "game.hpp" #include "timing.hpp" #include "game.hpp" #include "id.hpp" #include "pmenu.hpp" #include "gui.hpp" #include "property.hpp" #include "dev.hpp" #include "clisp.hpp" #include "gamma.hpp" #include "dprint.hpp" #include "demo.hpp" #include "loadgame.hpp" #include "scroller.hpp" #include "netcfg.hpp" #include "key_cfg.hpp" #include "mono_cfg.hpp" #include #include "sock.hpp" #ifdef __MAC__ #include "hack.hpp" #else #include "../imlib/port/mac/hack.hpp" inline void MacKeyConfigMenu() { ; } inline void MacPreferences() { ; } #endif #include "macgame.hpp" extern net_protocol *prot; jwindow *volume_window=NULL; jwindow *macpref_window=NULL; jwindow *key_window=NULL; extern int confirm_quit(); extern int registered; //percent is 0..256 void tint_area(int x1, int y1, int x2, int y2, int r_to, int g_to, int b_to, int percent) { int x,y; short cx1,cy1,cx2,cy2; screen->get_clip(cx1,cy1,cx2,cy2); if (x1cx2) x2=cx2; if (y2>cy2) y2=cy2; if (x2scan_line(y)+x1; for (x=x1;x<=x2;x++,sl++) { unsigned char *paddr=(unsigned char *)pal->addr()+(*sl)*3; unsigned char r=((*(paddr++))-r_to)*percent/256+r_to; unsigned char g=((*(paddr++))-g_to)*percent/256+g_to; unsigned char b=((*(paddr++))-b_to)*percent/256+b_to; *sl=color_table->lookup_color((r)>>3,(g)>>3,(b)>>3); } } screen->add_dirty(x1,y1,x2,y2); } void darken_area(int x1, int y1, int x2, int y2, int amount) { int x,y; short cx1,cy1,cx2,cy2; screen->get_clip(cx1,cy1,cx2,cy2); if (x1cx2) x2=cx2; if (y2>cy2) y2=cy2; if (x2scan_line(y)+x1; for (x=x1;x<=x2;x++,sl++) { unsigned char *paddr=(unsigned char *)pal->addr()+(*sl)*3; unsigned char r=(*(paddr++))*amount/256; unsigned char g=(*(paddr++))*amount/256; unsigned char b=(*(paddr++))*amount/256; *sl=color_table->lookup_color((r)>>3,(g)>>3,(b)>>3); } } screen->add_dirty(x1,y1,x2,y2); } void dark_wiget(int x1, int y1, int x2, int y2, int br, int dr, int amount) { screen->add_dirty(x1,y1,x2,y2); screen->line(x1,y1,x1,y2,br); screen->line(x1+1,y1,x2,y1,br); screen->line(x2,y1+1,x2,y2,dr); screen->line(x1+1,y2,x2,y2,dr); darken_area(x1+1,y1+1,x2-1,y2-1,amount); } char *men_str(void *arg) { switch (item_type(arg)) { case L_STRING : { return lstring_value(arg); } break; case L_CONS_CELL : { return lstring_value(CAR(arg)); } break; default : { lprint(arg); dprintf(" is not a valid menu option\n"); exit(0); } } return NULL; } void main_menu(); int menu(void *args, JCFont *font) // reurns -1 on esc { main_menu(); char *title=NULL; if (!NILP(CAR(args))) title=lstring_value(CAR(args)); Cell *def=lcar(lcdr(lcdr(args))); args=CAR(CDR(args)); int options=list_length(args); int mh=(font->height()+1)*options+10,maxw=0; Cell *c=(Cell *)args; for (;!NILP(c);c=CDR(c)) { if (strlen(men_str(CAR(c)))>maxw) maxw=strlen(men_str(CAR(c))); } int mw=(font->width())*maxw+20; int mx=screen->width()/2-mw/2, my=screen->height()/2-mh/2; screen->add_dirty(mx,my,mx+mw-1,my+mh-1); if (title) { int tl=strlen(title)*font->width(); int tx=screen->width()/2-tl/2; dark_wiget(tx-2,my-font->height()-4,tx+tl+2,my-2,eh->medium_color(),eh->dark_color(),180); font->put_string(screen,tx+1,my-font->height()-2,title,eh->bright_color()); } dark_wiget(mx,my,mx+mw-1,my+mh-1,eh->medium_color(),eh->dark_color(),200); int y=my+5; for (c=(Cell *)args;!NILP(c);c=CDR(c)) { char *ms=men_str(CAR(c)); font->put_string(screen,mx+10+1,y+1,ms,eh->black()); font->put_string(screen,mx+10,y,ms,eh->bright_color()); y+=font->height()+1; } eh->flush_screen(); event ev; int choice=0,done=0; int bh=font->height()+3; image *save=new image(mw-2,bh); int color=128,cdir=50; time_marker *last_color_time=NULL; if (!NILP(def)) choice=lnumber_value(def); do { eh->flush_screen(); if (eh->event_waiting()) { eh->get_event(ev); if (ev.type==EV_KEY) { switch (ev.key) { case JK_ESC : { choice=-1; done=1; } break; case JK_ENTER : { done=1; } break; case JK_DOWN : { if (choice0) choice--; else choice=options-1; } break; } } else if (ev.type==EV_MOUSE_BUTTON && ev.mouse_button) { if (ev.mouse_move.x>mx && ev.mouse_move.xmy && ev.mouse_move.yheight()+1); if (msel>=options) msel=options-1; if (msel==choice) // clicked on already selected item, return it done=1; else choice=msel; // selects an item } } } time_marker cur_time; if (!last_color_time || (int)(cur_time.diff_time(last_color_time)*1000)>120) { if (last_color_time) delete last_color_time; last_color_time=new time_marker; int by1=(font->height()+1)*choice+my+5-2; int by2=by1+bh-1; screen->put_part(save,0,0,mx+1,by1,mx+mw-2,by2); tint_area(mx+1,by1,mx+mw-2,by2,63,63,63,color); char *cur=men_str(nth(choice,args)); font->put_string(screen,mx+10+1,by1+3,cur,eh->black()); font->put_string(screen,mx+10,by1+2,cur,eh->bright_color()); screen->rectangle(mx+1,by1,mx+mw-2,by2,eh->bright_color()); color+=cdir; if (color<12 || color>256) { cdir=-cdir; color+=cdir; } eh->flush_screen(); save->put_image(screen,mx+1,by1); } else milli_wait(10); } while (!done); if (last_color_time) delete last_color_time; delete save; the_game->draw(the_game->state==SCENE_STATE); if (choice!=-1) { void *val=nth(choice,args); if (item_type(val)==L_CONS_CELL) // is there another value that the user want us to return? return lnumber_value(lcdr(val)); } return choice; } static void draw_vol(image *screen, int x1, int y1, int x2, int y2, int t, int max, int c1, int c2, int slider) { int dx=x1+t*(x2-x1)/max; if (t!=0) { cash.img(slider)->put_image(screen,x1,y1); // screen->bar(x1,y1,dx,y2,c1); } else dx--; if (dxbar(dx+1,y1,x2,y2,c2); } static void draw_sfx_vol(int slider) { draw_vol(volume_window->screen,16,75,99,88,sfx_volume,127,pal->find_closest(200,75,19), pal->find_closest(40,0,0),slider); } static void draw_music_vol(int slider) { draw_vol(volume_window->screen,6,61,34,67,music_volume,127,pal->find_closest(255,0,0), pal->find_closest(40,0,0),slider); } static void create_volume_window() { /* int vx=WINDOW_FRAME_LEFT,vy=WINDOW_FRAME_TOP+eh->font()->height()*2,scroller_height=130,bh=eh->font()->height()+5; volume_window=eh->new_window(prop->getd("volume_x",xres/2-20), prop->getd("volume_y",yres/2-50), -1, -1, new scroller(vx,vy,LOWER_SFX,0,scroller_height,0,127, new scroller(vx+30,vy,LOWER_MUSIC,0,scroller_height,0,127,NULL)),symbol_str("VOLUME")); event ev; int done=0; do { eh->flush_screen(); eh->get_event(ev); if (ev.type==EV_CLOSE_WINDOW && ev.window==volume_window) done=1; } while (!done); eh->close_window(volume_window); volume_window=NULL; */ char *ff="art/frame.spe"; int t=SPEC_IMAGE; int u_u=cash.reg(ff,"u_u",t,1), u_d=cash.reg(ff,"u_u",t,1), u_ua=cash.reg(ff,"u_ua",t,1), u_da=cash.reg(ff,"u_da",t,1), d_u=cash.reg(ff,"d_u",t,1), d_d=cash.reg(ff,"d_u",t,1), d_ua=cash.reg(ff,"d_ua",t,1), d_da=cash.reg(ff,"d_da",t,1), slider=cash.reg(ff,"volume_slide",t,1); image *ok_image=cash.img(cash.reg("art/frame.spe","dev_ok",SPEC_IMAGE,1))->copy(); volume_window=eh->new_window(prop->getd("volume_x",xres-185), prop->getd("volume_y",yres/2-50), 120-WINDOW_FRAME_LEFT-WINDOW_FRAME_RIGHT-2, 163-WINDOW_FRAME_TOP-WINDOW_FRAME_BOTTOM, new ico_button(62,112,ID_SFX_DOWN,d_u,d_d,d_ua,d_da, new ico_button(24,18,ID_SFX_UP,u_u,u_d,u_ua,u_da, new button(17,127,ID_QUIT_OK,ok_image, new info_field(35,0,0,symbol_str("SFXv"),0))))); /* new ico_button(10,72,ID_MUSIC_DOWN,d_u,d_d,d_ua,d_da, new ico_button(21,72,ID_MUSIC_UP,u_u,u_d,u_ua,u_da, new info_field(3,86,0,symbol_str("MUSICv"), NULL))))))); */ cash.img(cash.reg(ff,"vcontrol",t,1))->put_image(volume_window->screen,0,0); // draw_music_vol(slider); draw_sfx_vol(slider); volume_window->inm->redraw(); eh->grab_focus(volume_window); eh->flush_screen(); volume_window->inm->allow_no_selections(); volume_window->inm->clear_current(); event ev; do { do { eh->get_event(ev); } while (ev.type==EV_MOUSE_MOVE && eh->event_waiting()); eh->flush_screen(); if (ev.type==EV_MESSAGE) { switch (ev.message.id) { case ID_SFX_UP : { if (volume_window) { sfx_volume+=16; if (sfx_volume>127) sfx_volume=127; draw_sfx_vol(slider); char *s="sfx/ambtech1.wav"; if (sound_avail&SFX_INITIALIZED) cash.sfx(cash.reg(s,s,SPEC_EXTERN_SFX,1))->play(sfx_volume); } } break; case ID_SFX_DOWN : { if (volume_window) { sfx_volume-=16; if (sfx_volume<0) sfx_volume=0; draw_sfx_vol(slider); char *s="sfx/ambtech1.wav"; if (sound_avail&SFX_INITIALIZED) cash.sfx(cash.reg(s,s,SPEC_EXTERN_SFX,1))->play(sfx_volume); } } break; case ID_MUSIC_UP : { if (volume_window) { music_volume+=16; if (music_volume>127) music_volume=127; draw_music_vol(slider); if (current_song) current_song->set_volume(music_volume); } } break; case ID_MUSIC_DOWN : { if (volume_window) { music_volume-=16; if (music_volume<0) music_volume=0; draw_music_vol(slider); if (current_song) current_song->set_volume(music_volume); } } break; case ID_QUIT_OK : { eh->close_window(volume_window); volume_window=NULL; } } } else if (ev.type==EV_CLOSE_WINDOW || (ev.type==EV_KEY && ev.key==JK_ESC)) { eh->close_window(volume_window); volume_window=NULL; } } while (volume_window); delete ok_image; } FILE *open_FILE(char *filename, char *mode); void save_difficulty() { FILE *fp=open_FILE("hardness.lsp","wb"); if (!fp) dprintf("Unable to write to file hardness.lsp\n"); else { fprintf(fp,"(setf difficulty '"); if (DEFINEDP(symbol_value(l_difficulty))) { if (symbol_value(l_difficulty)==l_extreme) fprintf(fp,"extreme)\n"); else if (symbol_value(l_difficulty)==l_hard) fprintf(fp,"hard)\n"); else if (symbol_value(l_difficulty)==l_easy) fprintf(fp,"easy)\n"); else fprintf(fp,"medium)\n"); } else fprintf(fp,"medium)\n"); fclose(fp); } } void fade_out(int steps); void fade_in(image *im, int steps); #ifdef __MAC__ void RestoreMac(); void UnRestoreMac(); #else inline void RestoreMac() { ; } inline void UnRestoreMac() { ; } #endif int text_draw(int y, int x1, int y1, int x2, int y2, char *buf, JCFont *font, uchar *cmap, char color); void show_sell(int abortable) { #if 0 void *ss=make_find_symbol("sell_screens"); if (!DEFINEDP(symbol_value(ss))) { int sp=current_space; current_space=PERM_SPACE; // char *prog="((\"art/help.spe\" . \"sell2\")(\"art/help.spe\" . \"sell4\")(\"art/help.spe\" . \"sell3\")(\"art/endgame.spe\" . \"credit\"))"; char *prog="((\"art/endgame.spe\" . \"credit\") (\"art/help.spe\" . \"sell6\"))"; set_symbol_value(ss,compile(prog)); current_space=sp; } if (DEFINEDP(symbol_value(ss))) { image blank(2,2); blank.clear(); eh->set_mouse_shape(blank.copy(),0,0); // don't show mouse ss=symbol_value(ss); int quit=0; while (ss && !quit) { int im=cash.reg_object("art/help.spe",CAR(ss),SPEC_IMAGE,1); fade_in(cash.img(im),16); event ev; do { eh->flush_screen(); eh->get_event(ev); } while (ev.type!=EV_KEY); if (ev.key==JK_ESC && abortable) quit=1; fade_out(16); ss=CDR(ss); } eh->set_mouse_shape(cash.img(c_normal)->copy(),1,1); } #else image blank(2,2); blank.clear(); eh->set_mouse_shape(blank.copy(),0,0); // don't show mouse screen->clear(); image *im; event ev; int i; im=cash.img(cash.reg("art/endgame.spe","credit",SPEC_IMAGE,1)); char *str=lstring_value(eval(make_find_symbol("thanks_text"))); int dx=(xres+1)/2-im->width()/2,dy=(yres+1)/2-im->height()/2; im->put_image(screen,dx,dy); fade_in(0,16); uchar cmap[32]; for (i=0;i<32;i++) cmap[i]=pal->find_closest(i*256/32,i*256/32,i*256/32); i = 0; int tx = 300, ty = 350, twx = 319, twy = 119; while (eh->event_waiting()) eh->get_event(ev); ev.type = EV_SPURIOUS; time_marker start; int txti = 0; do { im->put_part(screen,dx+tx,dy+ty,tx,ty,tx+twx,ty+twy); txti++; text_draw(twy+5-txti,dx+tx+15,dy+ty,dx+tx+twx-15,dy+ty+twy,str,eh->font(),cmap,eh->bright_color()); eh->flush_screen(); time_marker now; while (now.diff_time(&start)<0.10) now.get_time(); start.get_time(); while (eh->event_waiting() && ev.type!=EV_KEY) eh->get_event(ev); } while (txti<600 && ev.type!=EV_KEY && ev.type!=EV_MOUSE_BUTTON); fade_out(16); if (!abortable || !(ev.type==EV_KEY && ev.key==JK_ESC)) { im=cash.img(cash.reg("art/help.spe","sell6",SPEC_IMAGE,1)); fade_in(im,16); do { eh->flush_screen(); eh->get_event(ev); } while (ev.type!=EV_KEY && ev.type!=EV_MOUSE_BUTTON); fade_out(16); } eh->set_mouse_shape(cash.img(c_normal)->copy(),1,1); #endif } void menu_handler(event &ev, input_manager *inm) { switch (ev.type) { case EV_MESSAGE : { switch (ev.message.id) { case ID_LIGHT_OFF : if (!volume_window) { screen->clear(); eh->flush_screen(); gamma_correct(pal,1); fade_in(cash.img(title_screen),8); inm->redraw(); eh->flush_screen(); } break; case ID_RETURN : if (!volume_window) { the_game->set_state(RUN_STATE); } break; case ID_START_GAME : if (!volume_window) { the_game->load_level(level_file); the_game->set_state(RUN_STATE); view *v; for (v=player_list;v;v=v->next) if (v->focus) v->reset_player(); } break; case ID_LOAD_PLAYER_GAME : if (!volume_window) { int got_level=load_game(0,symbol_str("LOAD")); the_game->reset_keymap(); if (got_level) { char name[50]; sprintf(name,"save%04d.spe",got_level); the_game->load_level(name); the_game->set_state(RUN_STATE); } } break; case ID_VOLUME : if (!volume_window) { create_volume_window(); } break; case ID_MEDIUM : { set_symbol_value(l_difficulty,l_medium); save_difficulty(); } break; case ID_HARD : { set_symbol_value(l_difficulty,l_hard); save_difficulty(); } break; case ID_EXTREME : { set_symbol_value(l_difficulty,l_extreme); save_difficulty(); } break; case ID_EASY : { set_symbol_value(l_difficulty,l_easy); save_difficulty(); } break; case ID_NETWORKING : { if (!volume_window) { net_configuration *cfg=new net_configuration; if (cfg->input()) { if (main_net_cfg) delete main_net_cfg; main_net_cfg=cfg; } else delete cfg; the_game->draw(0); inm->redraw(); } } break; case ID_SHOW_SELL : if (!volume_window) { show_sell(1); screen->clear(); if (title_screen>=0) { image *tit=cash.img(title_screen); tit->put_image(screen,screen->width()/2-tit->width()/2, screen->height()/2-tit->height()/2); } inm->redraw(); fade_in(NULL,8); eh->flush_screen(); } break; case ID_MACKEYS : do_key_config(eh); /* fade_out(8); RestoreMac(); MacKeyConfigMenu(); UnRestoreMac(); */ fade_in(cash.img(title_screen),8); inm->redraw(); eh->flush_screen(); break; case ID_MACCONF : do_monitor_config(eh); fade_in(cash.img(title_screen),8); inm->redraw(); eh->flush_screen(); break; } break; } break; case EV_CLOSE_WINDOW : { if (ev.window==volume_window) { eh->close_window(volume_window); volume_window=NULL; } } break; } } void *current_demo=NULL; static ico_button *load_icon(int num, int id, int x, int y, int &h, ifield *next, char *key) { char name[20]; char *base="newi"; int a,b,c; sprintf(name,"%s%04d.pcx",base,num*3+1); a=cash.reg("art/icons.spe",name,SPEC_IMAGE,1); sprintf(name,"%s%04d.pcx",base,num*3+2); b=cash.reg("art/icons.spe",name,SPEC_IMAGE,1); sprintf(name,"%s%04d.pcx",base,num*3+3); c=cash.reg("art/icons.spe",name,SPEC_IMAGE,1); h=cash.img(a)->height(); return new ico_button(x,y,id,b,b,a,c,next,-1,key); } ico_button *make_default_buttons(int x,int &y, ico_button *append_list) { int h; int diff_on; if (DEFINEDP(symbol_value(l_difficulty))) { if (symbol_value(l_difficulty)==l_extreme) diff_on=3; else if (symbol_value(l_difficulty)==l_hard) diff_on=2; else if (symbol_value(l_difficulty)==l_easy) diff_on=0; else diff_on=1; } else diff_on=3; ico_button *start; ifield **cur=(ifield **)&start; if (!player_list->next) { *cur=load_icon(0,ID_START_GAME,x,y,h,NULL,"ic_start"); cur=&((*cur)->next); y+=h; } ico_switch_button *set=NULL; if (!main_net_cfg || (main_net_cfg->state!=net_configuration::SERVER && main_net_cfg->state!=net_configuration::CLIENT)) { *cur=new ico_switch_button(x,y,ID_NULL,diff_on, load_icon(3,ID_EASY,x,y,h, load_icon(8,ID_MEDIUM,x,y,h, load_icon(9,ID_HARD,x,y,h, load_icon(10,ID_EXTREME,x,y,h,NULL,"ic_extreme"), "ic_hard"),"ic_medium"),"ic_easy"),NULL); cur=&((*cur)->next); y+=h; } *cur=load_icon(4,ID_LIGHT_OFF,x,y,h,NULL,"ic_gamma"); cur=&((*cur)->next); y+=h; *cur=load_icon(5,ID_VOLUME,x,y,h,NULL,"ic_volume"); cur=&((*cur)->next); y+=h; if (registered && prot) { *cur = load_icon(11,ID_NETWORKING,x,y,h,NULL,"ic_networking"); cur=&((*cur)->next); y+=h; } *cur = load_icon(2,ID_SHOW_SELL,x,y,h,NULL,"ic_sell"); cur=&((*cur)->next); y+=h; *cur = load_icon(12,ID_MACCONF,x,y,h,NULL,"ic_macconf"); cur=&((*cur)->next); y+=h; *cur = load_icon(13,ID_MACKEYS,x,y,h,NULL,"ic_mackeys"); cur=&((*cur)->next); y+=h; *cur=load_icon(6,ID_QUIT,x,y,h,NULL,"ic_quit"); cur=&((*cur)->next); y+=h; ico_button *list=append_list; if (append_list) { while (append_list->next) append_list=(ico_button *)append_list->next; append_list->next=start; } else list=start; return list; } ico_button *make_conditional_buttons(int x,int &y) { ico_button *start_list=NULL; int h; if (current_level) // should we include a return icon? { start_list=load_icon(7,ID_RETURN,x,y,h,NULL,"ic_return"); y+=h; } ico_button *load; if (!player_list->next && show_load_icon()) { load= load_icon(1,ID_LOAD_PLAYER_GAME,x,y,h,NULL,"ic_load"); y+=h;} else load=NULL; if (start_list) start_list->next=load; else start_list=load; return start_list; } void main_menu() { int y=yres/2-210; ico_button *list=make_conditional_buttons(xres-51,y); list=make_default_buttons(xres-51,y,list); input_manager *inm=new input_manager(screen,eh,list); inm->allow_no_selections(); inm->clear_current(); time_marker old_time; screen->add_dirty(0,0,xres-1,yres-1); int eoff=0,coff=0; event ev; #ifdef __MAC__ int command = 0; #endif int state=0,stop_menu=0; time_marker start; eh->flush_screen(); do { time_marker new_time; if (eh->event_waiting()) { do { eh->get_event(ev); } while (ev.type==EV_MOUSE_MOVE && eh->event_waiting()); inm->handle_event(ev,NULL,eh); #ifdef __MAC__ if ((ev.type==EV_KEY || ev.type==EV_KEYRELEASE) && ev.key==JK_COMMAND) command = (ev.type == EV_KEY); if (ev.type==EV_KEY && ev.key=='q' && command) eh->push_event(new event(ID_QUIT,NULL)); #else if (ev.type==EV_KEY && ev.key==JK_ESC) eh->push_event(new event(ID_QUIT,NULL)); #endif menu_handler(ev,inm); start.get_time(); eh->flush_screen(); } if (new_time.diff_time(&start)>22) { if (volume_window) start.get_time(); else { if (!current_demo) { void *d=make_find_symbol("demos"); if (DEFINEDP(symbol_value(d))) current_demo=symbol_value(d); } if (current_demo) { demo_man.set_state(demo_manager::PLAYING,lstring_value(CAR(current_demo))); stop_menu=1; current_demo=CDR(current_demo); } } } if (volume_window) stop_menu=0; // can't exit with colume window open else if (main_net_cfg && main_net_cfg->restart_state()) stop_menu=1; else if (the_game->state==RUN_STATE) stop_menu=1; else if (ev.type==EV_MESSAGE) { if (ev.message.id==ID_START_GAME || ev.message.id==ID_RETURN) stop_menu=1; else if (ev.message.id==ID_QUIT) { #ifdef __MAC__ stop_menu=1; #else if (confirm_quit()) stop_menu=1; else { ev.type=EV_SPURIOUS; start.get_time(); } #endif } } } while (!stop_menu); delete inm; if (ev.type==EV_MESSAGE && ev.message.id==ID_QUIT) // propogate the quit message the_game->end_session(); }