#include "menu.hpp" #include "lisp.hpp" #include "loader.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 jwindow *volume_window=NULL; //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); printf(" 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 { 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 } } eh->flush_screen(); } 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; } struct mask_line { int x,size; ushort *remap; } ; void scan_map(image *screen, int sx, int sy, image *im, image *clouds, mask_line *p, int mask_height, int xoff, int coff) { int x1=10000,x2=0; int iw=im->width(); ushort r,co,off,cc; int y=0; for (;yscan_line(y+sy)+sx+n->x; uchar *sl2=im->scan_line(y); // uchar *sl3=clouds->scan_line(y); ushort *rem=n->remap; if (sx+n->xx; int x=0; for (;xsize;x++,sl++,rem++) { r=*rem; // co=(r+coff); // if (co>=iw) co-=iw; // cc=sl3[co]; off=(r+xoff); if (off>=iw) off-=iw; // if (cc) // *sl=*(white_light+(r/4+(x+y)%2)*256+*(white_light+((256-cc)/2-64)*256+sl2[off])); // *sl=*(white_light+(r/4+(x+y)%2)*256+*(white_light+(48+cc/16)*256+sl2[off])); // else *sl=*(white_light+(r/4+(x+y)%2)*256+sl2[off]); } if (sx+n->x+x>x2) x2=sx+n->x+x; } screen->add_dirty(x1,sy,x2,sy+mask_height-1); } mask_line *make_mask_lines(image *mask, int map_width) { mask_line *p=(mask_line *)jmalloc(mask->height()*sizeof(mask_line),"mask_line"); for (int y=0;yheight();y++) { // find the start of the run.. uchar *sl=mask->scan_line(y); int x=0; while (*sl==0) { sl++; x++; } p[y].x=x; // find the length of the run int size=0; while (*sl!=0 && xwidth()) { sl++; x++; size++; } p[y].size=size; // now calculate remap for line p[y].remap=(ushort *)jmalloc(size*2,"mask remap"); ushort *rem=p[y].remap; for (x=0;xwidth()-(sqrt((size-x)/(double)size)*map_width/2.0)+mask->width()/2); } } return p; } static void draw_vol(image *screen, int x1, int y1, int x2, int y2, int t, int max, int c1, int c2) { int dx=x1+t*(x2-x1)/max; if (t!=0) screen->bar(x1,y1,dx,y2,c1); else dx--; if (dxbar(dx+1,y1,x2,y2,c2); } static void draw_sfx_vol() { draw_vol(volume_window->screen,5,17,34,23,sfx_volume,127,pal->find_closest(255,0,0), pal->find_closest(90,0,0)); } static void draw_music_vol() { draw_vol(volume_window->screen,5,72,34,78,music_volume,127,pal->find_closest(255,0,0), pal->find_closest(90,0,0)); } static void create_volume_window() { 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); volume_window=eh->new_window(prop->getd("volume_x",xres/2-20), prop->getd("volume_y",yres/2-50), 41-WINDOW_FRAME_LEFT-WINDOW_FRAME_RIGHT, 101-WINDOW_FRAME_TOP-WINDOW_FRAME_BOTTOM, new ico_button(10,27,ID_SFX_DOWN,d_u,d_d,d_ua,d_da, new ico_button(21,27,ID_SFX_UP,u_u,u_d,u_ua,u_da, new ico_button(10,63,ID_MUSIC_DOWN,d_u,d_d,d_ua,d_da, new ico_button(21,63,ID_MUSIC_UP,u_u,u_d,u_ua,u_da, NULL))))); cash.img(cash.reg(ff,"vcontrol",t,1))->put_image(volume_window->screen,0,0); draw_music_vol(); draw_sfx_vol(); volume_window->inm->redraw(); eh->grab_focus(volume_window); } #define MENU_TICONS 19 int menu_icons[MENU_TICONS*3]; int menu_icons_ids[MENU_TICONS]={ID_START_GAME,ID_VOLUME,ID_NULL,ID_NULL,ID_NULL,ID_NULL, ID_NULL,ID_NULL,ID_QUIT,ID_NULL,ID_EASY,ID_NULL, ID_MEDIUM,ID_NULL,ID_HARD,ID_NULL,ID_LIGHT_ON,ID_LIGHT_OFF, ID_EXTREME }; static jwindow *ico_win; void save_difficulty() { FILE *fp=fopen("hardness.lsp","wb"); if (!fp) dprintf("Unable to write to file hardness.lsp\n"); else { fprintf(fp,"(setf difficulty '"); if (DEFINEDP(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 menu_handler(event &ev, jwindow *ico_win) { switch (ev.type) { case EV_MESSAGE : { switch (ev.message.id) { case ID_LIGHT_OFF : { gamma_correct(pal,1); } break; case ID_START_GAME : { the_game->load_level(level_file); the_game->set_state(RUN_STATE); } break; case ID_VOLUME : { create_volume_window(); } break; case ID_SFX_UP : { if (volume_window) { sfx_volume+=16; if (sfx_volume>127) sfx_volume=127; draw_sfx_vol(); } } break; case ID_SFX_DOWN : { if (volume_window) { sfx_volume-=16; if (sfx_volume<0) sfx_volume=0; draw_sfx_vol(); } } break; case ID_MUSIC_UP : { if (volume_window) { music_volume+=16; if (music_volume>127) music_volume=127; draw_music_vol(); } } break; case ID_MUSIC_DOWN : { if (volume_window) { music_volume-=16; if (music_volume<0) music_volume=0; draw_music_vol(); } } 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; } break; } break; case EV_CLOSE_WINDOW : { if (ev.window==volume_window) { eh->close_window(volume_window); volume_window=NULL; } } break; } } void *current_demo=NULL; void main_menu() { image *Earth=cash.img(earth); image *Emap=cash.img(earth_mask); char name[20]; ico_button *buts[MENU_TICONS]; long maxx=0,maxy=0; int i=0; for (;iwidth(); long y=WINDOW_FRAME_TOP+(i/9)*cash.img(menu_icons[0])->height(); if (x>maxx) maxx=x; if (y>maxy) maxy=y; buts[i]=new ico_button(x,y,menu_icons_ids[i], menu_icons[i*3],menu_icons[i*3], menu_icons[i*3+1],menu_icons[i*3+2],NULL); } buts[0]->next=buts[1]; int b1,b2,b3,b4; if (DEFINEDP(symbol_value)) { if (symbol_value(l_difficulty)==l_extreme) { b1=18; b2=10; b3=12; b4=14; } else if (symbol_value(l_difficulty)==l_hard) { b1=14; b2=18; b3=10; b4=12; } else if (symbol_value(l_difficulty)==l_easy) { b1=10; b2=12; b3=14; b4=18; } else { b1=12; b2=14; b3=18; b4=10; } } else { b1=12; b2=14; b3=18; b4=10; } buts[b1]->next=buts[b2]; buts[b2]->next=buts[b3]; buts[b3]->next=buts[b4]; buts[1]->next=new ico_switch_button(buts[0]->X(), buts[0]->Y()+cash.img(menu_icons[0])->height()*2, ID_NULL, buts[b1],buts[17]); buts[17]->next=buts[8]; buts[1]->set_xy(buts[0]->X(), buts[0]->Y()+cash.img(menu_icons[0])->height()*1); buts[12]->set_xy(buts[0]->X(), buts[0]->Y()+cash.img(menu_icons[0])->height()*2); buts[17]->set_xy(buts[0]->X(), buts[0]->Y()+cash.img(menu_icons[0])->height()*3); buts[8]->set_xy(buts[0]->X(), buts[0]->Y()+cash.img(menu_icons[0])->height()*4); ico_win=eh->new_window(-1,yres/2-80,-1,-1,buts[0],"Menu"); // pmenu *main_pm=new pmenu(0,0,game_sub,screen,eh); time_marker old_time; screen->add_dirty(0,0,319,199); // create sphere map mask_line *p=make_mask_lines(Emap,Earth->width()); int eoff=0,coff=0; event ev; // main_pm->draw(screen,eh,1); long x=84,y=60; Cell *v=find_symbol("earth_x"); if (v && DEFINEDP(v)) x=lnumber_value(symbol_value(v)); v=find_symbol("earth_y"); if (v && DEFINEDP(v)) y=lnumber_value(symbol_value(v)); int state=0,stop_menu=0; time_marker start; do { time_marker new_time; if (state || new_time.diff_time(&old_time)>0.15) { old_time.get_time(); scan_map(screen,x,y,Earth,NULL,p,Emap->height(),eoff,coff); if (state) { eoff+=8; coff+=4; } else { eoff+=2; coff+=1; } if (eoff>=320) eoff-=320; if (coff>=320) coff-=320; eh->flush_screen(); } if (eh->event_waiting()) { eh->get_event(ev); start.get_time(); // reset time till demo starts up menu_handler(ev,ico_win); if (ev.type==EV_MOUSE_BUTTON && ev.mouse_button && ev.mouse_move.x>=x && ev.mouse_move.y>=y && ev.mouse_move.x<=x+Emap->width() && ev.mouse_move.y<=y+Emap->height()) { state=1; } else if (ev.type==EV_MOUSE_BUTTON && !ev.mouse_button) state=0; eh->flush_screen(); } if (new_time.diff_time(&start)>10) { if (!current_demo) { void *d=make_find_symbol("demos"); if (DEFINEDP(d)) current_demo=symbol_value(d); } if (current_demo) { if (set_demo_mode(DEMO_PLAY,lstring_value(CAR(current_demo)),eh)) stop_menu=1; current_demo=CDR(current_demo); } } } while (!stop_menu && (ev.type!=EV_MESSAGE || (ev.message.id!=ID_START_GAME && ev.message.id!=ID_QUIT))); for (i=0;iinm->unlink(menu_icons_ids[i]); if (i) delete ic; else delete buts[i]; } eh->close_window(ico_win); for (int xx=0;xxheight();xx++) jfree(p[xx].remap); jfree(p); if (ev.message.id==ID_QUIT) // propogate the quit message the_game->end_session(); // delete main_pm; } /* pmenu_item *net_sub=new pmenu_item("Multiplayer", new psub_menu( new pmenu_item(ID_MODEM, "Modem",-1, new pmenu_item(ID_TCPIP, "TCP/IP (internet)",-1, new pmenu_item(ID_IPX, "IPX",-1, new pmenu_item(ID_SPLIT_SCREEN, "Split screen",-1, NULL)))),NULL),NULL,200); pmenu_item *graphics_sub=new pmenu_item("Options", new psub_menu( new pmenu_item(ID_KEY_SETUP, "Keyboard",-1, new pmenu_item(ID_MOUSE_SETUP, "Mouse",-1, new pmenu_item(CALB_JOY, "Joystick",-1, new pmenu_item(0, NULL, -1, new pmenu_item(ID_LIGHT_DETAIL, "Lighting detail",-1, new pmenu_item(ID_SCREEN_SIZE, "Screen Size",-1, new pmenu_item(ID_VOLUME, "Volume",-1, new pmenu_item(ID_SFX_CHANNELS, "Sfx Channels",-1, NULL)))))))),NULL),net_sub,100); pmenu_item *game_sub=new pmenu_item("Game", new psub_menu( new pmenu_item(ID_NEW_GAME, "New Game",-1, new pmenu_item(ID_DIFFICULTY,"Difficulty",-1, new pmenu_item(ID_LOAD_GAME, "Load Game",-1, new pmenu_item(ID_QUIT, "Quit",-1,NULL)))),NULL),graphics_sub,27); */