source: abuse/trunk/src/game.cpp @ 30

Last change on this file since 30 was 17, checked in by Sam Hocevar, 17 years ago
  • absolute shitloads of 64 bit fixes.
File size: 62.7 KB
Line 
1#include "game.hpp"
2#include "dev.hpp"
3#include "id.hpp"
4#include "joy.hpp"
5#include "timing.hpp"
6#include "automap.hpp"
7#include "help.hpp"
8#include "ability.hpp"
9#include "cache.hpp"
10#include "loader.hpp"
11#include "lisp.hpp"
12#include "monoprnt.hpp"
13#include "jrand.hpp"
14#include "config.hpp"
15#include "light.hpp"
16#include "scroller.hpp"
17#include "dprint.hpp"
18#include "nfserver.hpp"
19#include "video.hpp"
20#include "transp.hpp"
21#include "clisp.hpp"
22#include "guistat.hpp"
23#include "menu.hpp"
24#include "gamma.hpp"
25#include "lisp_gc.hpp"
26#include "demo.hpp"
27#include "sbar.hpp"
28#include "profile.hpp"
29#include "compiled.hpp"
30#include "lisp_gc.hpp"
31#include "pmenu.hpp"
32#include "timing.hpp"
33#include "chat.hpp"
34#include "demo.hpp"
35#include "netcfg.hpp"
36
37//#ifdef __POWERPC__
38//#include <profiler.h>  //prof
39//#endif
40
41#include <ctype.h>
42#include <setjmp.h>
43
44#ifdef __APPLE__
45// SDL for OSX needs to override main()
46#include <SDL.h>
47#endif
48
49#define SHIFT_RIGHT_DEFAULT 0
50#define SHIFT_DOWN_DEFAULT 30
51
52class game;
53extern crc_manager *net_crcs;
54extern void show_verinfo(int argc, char **argv);
55game *the_game;
56window_manager *eh=NULL;
57int dev,shift_down=SHIFT_DOWN_DEFAULT,shift_right=SHIFT_RIGHT_DEFAULT;
58double sum_diffs=1,total_diffs=12;
59int total_active=0;
60int32_t map_xoff=0,map_yoff=0;
61int32_t current_vxadd,current_vyadd;
62int frame_panic=0,massive_frame_panic=0;
63int demo_start=0,idle_ticks=0;
64int req_end=0;
65
66extern palette *old_pal;
67char **start_argv;
68int start_argc;
69int has_joystick=0;
70char req_name[100];
71
72int registered=0;
73extern uint8_t chatting_enabled;
74
75extern int confirm_quit();
76
77#if (defined(__APPLE__) && !defined(__MACH__))
78extern char *macify_name(char *s);
79#endif
80
81// Enabled TCPIP driver
82#include "tcpip.hpp"
83tcpip_protocol tcpip;
84
85FILE *open_FILE(char *filename, char *mode)
86{
87/*  char *prefix=get_filename_prefix() ? get_filename_prefix() : "",*c;
88 
89  if (get_save_filename_prefix)
90  {
91    for (c=mode;*c;c++)
92      if (c=='w' || c=='W')
93      {
94      }
95  } */
96     
97 
98  char tmp_name[200];
99  if (get_filename_prefix() && filename[0] != '/')
100    sprintf(tmp_name,"%s%s",get_filename_prefix(),filename);
101  else strcpy(tmp_name,filename);
102#if (defined(__APPLE__) && !defined(__MACH__))
103  macify_name(tmp_name);
104#endif
105  return fopen(tmp_name,mode);
106}
107
108
109void handle_no_space()
110{
111  char *no_space_msg= "\nYou are out of disk space or the game\n"
112                      "was unable to write to disk for some reason\n"
113                      "The game cannot continue, please check this out\n"
114                      "and try again.\n";
115  if (eh)
116  {
117    jwindow *no_space=eh->new_window(0,0,-1,-1,
118                                     new button(WINDOW_FRAME_LEFT,WINDOW_FRAME_TOP,ID_QUIT_OK,"Quit",
119                                                new info_field(WINDOW_FRAME_LEFT,WINDOW_FRAME_TOP+eh->font()->height()*2,ID_NULL,
120                                                              no_space_msg,NULL)),"ERROR");
121    event ev;
122    do
123    {
124      eh->flush_screen();
125      eh->get_event(ev);
126    } while (ev.type!=EV_MESSAGE || ev.message.id!=ID_QUIT_OK);
127    eh->close_window(no_space);
128
129    close_graphics();
130    exit(1);
131  } else
132  {
133    fprintf(stderr,"%s\n",no_space_msg);
134    exit(0);
135  }
136}
137
138void game::play_sound(int id, int vol, int32_t x, int32_t y)
139{
140        if( sound_avail & SFX_INITIALIZED )
141        {
142                if( vol < 15 )
143                        return;
144                if( !player_list )
145                        return;
146
147                uint32_t mdist = 0xffffffff;
148                view *cd = NULL;
149                for( view *f = player_list; f ; f = f->next )
150                {
151                        if( f->local_player() )
152                        {
153                                int32_t cx = abs(f->x_center()-x),cy = abs(f->y_center()-y), d;
154                                if( cx < cy )
155                                        d = cx + cy - ( cx >> 1 );
156                                else
157                                        d = cx + cy - ( cy >> 1 );
158
159                                if( (unsigned)d < mdist )
160                                {
161                                        cd = f;
162                                        mdist = d;
163                                }
164                        }
165                }
166                if( mdist > 500 || !cd )
167                        return;
168                if( mdist < 100 )
169                        mdist = 0;
170                else
171                        mdist -= 100;
172
173                int v = ( 400 - mdist ) * sfx_volume / 400 - ( 127 - vol );
174
175                // Calculate the position of the sound relative to the player
176                int p = cd->x_center() - x;
177                if( p > 0 )
178                        p = (int)( ( (double)p / 255.0 ) * 128.0 );
179                else
180                        p = (int)( ( (double)abs(p) / 255.0 ) * -128.0 );
181                p+=128;
182                if( p < 0 ) p = 0;
183                if( p > 255 ) p = 255;
184
185                if( v > 0 )
186                        cash.sfx(id)->play( v, 128, p );
187        }
188}
189
190int get_option( char *name )
191{
192        int i;
193        for( i = 1; i < start_argc; i++ )
194        {
195                if( !strcmp( start_argv[i], name ) )
196                {
197                        return i;
198                }
199        }
200        return 0;
201}
202
203
204void make_screen_size(int w, int h)
205{
206        for( view *f = player_list; f; f = f->next )
207        {
208                if( f->local_player() )
209                {
210                        if( (unsigned)w >= xres - 1 )
211                                w = xres - 2;
212                        if( (unsigned)h >= yres - 1 )
213                                h = yres - 2;
214                        f->suggest.cx1 = ( xres + 1 ) / 2 - w / 2;
215                        f->suggest.cx2 = ( xres + 1 ) / 2 + w / 2;
216                        f->suggest.cy1 = ( yres - 31 ) / 2 + 5 - h / 2;
217                        f->suggest.cy2 = ( yres - 51 ) / 2 + 5 + h / 2;
218                        f->suggest.shift_down = f->shift_down;
219                        f->suggest.shift_right = f->shift_right;
220                        f->suggest.pan_x = f->pan_x;
221                        f->suggest.pan_y = f->pan_y;
222                        f->suggest.send_view = 1;
223                }
224        }
225}
226
227void game::grow_views(int amount)
228{
229  view *f=first_view;
230  for (;f;f=f->next)
231  {
232    if (f->local_player())
233    {
234      f->suggest.cx1=(f->cx1-amount);
235      f->suggest.cy1=f->cy1-amount/2;
236      f->suggest.cx2=(f->cx2+amount);
237      f->suggest.cy2=f->cy2+amount/2;
238      f->suggest.shift_down=f->shift_down;
239      f->suggest.shift_right=f->shift_right;
240      f->suggest.pan_x=f->pan_x;
241      f->suggest.pan_y=f->pan_y;
242
243      f->suggest.send_view=1;
244    }
245  }
246
247
248  for (f=first_view;f;f=f->next) 
249  {
250    if (f->local_player())
251    {
252      if (f->suggest.cx2-f->suggest.cx1<20 || f->suggest.cy2-f->suggest.cy1<15 ||
253        f->suggest.cx1<0 || f->suggest.cy1<0) f->suggest.send_view=0;
254      if (f->next && f->next->local_player() && f->suggest.cy2>=f->next->cy1) f->suggest.send_view=0;
255    }
256  }
257}
258
259void game::pan( int xv, int yv )
260{
261        first_view->pan_x += xv;
262        first_view->pan_y += yv;
263}
264
265view *game::view_in(int mousex, int mousey)
266{
267  for (view *f=first_view;f;f=f->next)
268    if (f->drawable() && mousex>=f->cx1 && mousey>=f->cy1 && mousex<=f->cx2 && mousey<=f->cy2)
269      return f;
270  return NULL;
271}
272
273int playing_state(int state)
274{
275  if (state==RUN_STATE || state==PAUSE_STATE) return 1;
276  else return 0;
277}
278
279void game::ftile_on(int screenx, int screeny, int32_t &x, int32_t &y)
280{
281  mouse_to_game(screenx,screeny,x,y);
282  x/=ftile_width();
283  y/=ftile_height();
284/*  view *f=view_in(screenx,screeny);
285  if (f)
286  {
287    x=((int32_t)(screenx)-(int32_t)f->cx1+f->xoff())/(int32_t)f_wid;
288    y=((int32_t)(screeny)-(int32_t)f->cy1+f->yoff())/(int32_t)f_hi;
289  }
290  else
291  {
292    x=-1;
293    y=-1;
294  }*/
295}
296
297void game::btile_on(int screenx, int screeny, int32_t &x, int32_t &y)
298{
299  view *f=view_in(screenx,screeny);
300  if (f)
301  {
302    x=((int32_t)(screenx)-(int32_t)f->cx1+f->xoff()*bg_xmul/bg_xdiv)/(int32_t)b_wid;
303    y=((int32_t)(screeny)-(int32_t)f->cy1+f->yoff()*bg_ymul/bg_ydiv)/(int32_t)b_hi;
304  }
305  else
306  {
307    x=-1;
308    y=-1;
309  }
310}
311
312
313void game::mouse_to_game(int32_t x, int32_t y, int32_t &gamex, int32_t &gamey, view *f)
314{
315  if (!f)
316  {
317    f=view_in(x,y);
318    if (!f) f=player_list;  // if not in a view use the first on
319  }
320
321  if (f)
322  {
323
324      if (dev&MAP_MODE)
325      {
326        gamex=((x-(int32_t)f->cx1)*ftile_width()/AUTOTILE_WIDTH+map_xoff*ftile_width());
327        gamey=((y-(int32_t)f->cy1)*ftile_height()/AUTOTILE_HEIGHT+map_yoff*ftile_height());
328      } else
329      {
330        gamex=(x-(int32_t)f->cx1+f->xoff());
331        gamey=(y-(int32_t)f->cy1+f->yoff());
332      }
333
334  }
335
336}
337
338void game::game_to_mouse(int32_t gamex, int32_t gamey, view *which, int32_t &x, int32_t &y)
339{
340  if (dev&MAP_MODE)
341  {
342    int32_t x1,y1;
343    if (dev&EDIT_MODE)
344    {
345      x1=map_xoff;
346      y1=map_yoff;
347    } else
348    {
349      if (which->focus)
350      {
351        x1=which->focus->x/ftile_width()-(which->cx2-which->cx1)/AUTOTILE_WIDTH/2;
352        y1=which->focus->y/ftile_height()-(which->cy2-which->cy1)/AUTOTILE_HEIGHT/2;
353      } else x1=y1=0;
354    }
355    if (x1<0) x1=0;
356    if (y1<0) y1=0;
357
358    x=gamex*AUTOTILE_WIDTH/ftile_width()-x1*AUTOTILE_WIDTH+which->cx1;
359    if (x1>0)
360      x-=((which->focus->x*AUTOTILE_WIDTH/ftile_width()) %AUTOTILE_WIDTH);
361
362    y=gamey*AUTOTILE_HEIGHT/ftile_height()-y1*AUTOTILE_HEIGHT+which->cy1;
363    if (y1>0)
364      y-=((which->focus->y*AUTOTILE_HEIGHT/ftile_height()) %AUTOTILE_HEIGHT);
365  }
366  else
367  {
368    x=gamex-which->xoff()+which->cx1;
369    y=gamey-which->yoff()+which->cy1;
370  }
371}
372
373int window_state(int state)
374{
375  switch (state)
376  {
377    case RUN_STATE :
378    case PAUSE_STATE :
379    case JOY_CALB_STATE :
380    { return 1; } break;
381
382    case INTRO_START_STATE :
383    case HELP_STATE :
384    case INTRO_MORPH_STATE :
385    case MENU_STATE :
386    case SCENE_STATE :
387    { return 0; } break;
388  }
389  return 1;
390}
391
392
393
394void game::set_state(int new_state)
395{
396  int d=0;
397  reset_keymap();                             // we think all the keys are up right now
398  if (playing_state(new_state) && !playing_state(state))
399  {
400    if (first_view && first_view!=player_list)
401    {
402      while (first_view)
403      {
404        view *tmp=first_view;
405        first_view=first_view->next;
406        delete tmp;
407      }
408      first_view=old_view;
409      old_view=NULL;
410    }
411    first_view=player_list;
412    d=1;
413  } else if (!playing_state(new_state) && (playing_state(state) || state==START_STATE))
414  {
415    if (player_list)   
416    {
417      first_view=new view(player_list->focus,NULL,-1);
418      first_view->pan_x=player_list->xoff();
419      first_view->pan_y=player_list->yoff();
420    }
421    else   
422      first_view=new view(NULL,NULL,0);
423    first_view->cx1=(xres+1)/2-155;
424    first_view->cy1=(yres+1)/2-95;
425    first_view->cx2=(xres+1)/2+155;
426    if (total_weapons)
427      first_view->cy2=(yres+1)/2+68;
428    else
429      first_view->cy2=(yres+1)/2+95;
430    d=1;
431  }
432 
433
434
435  // switching to/from scene mode cause the screen size to change and the border to change
436  // so we need to redraw.
437  if (window_state(new_state) && !window_state(state))
438    eh->show_windows();
439  else if (!window_state(new_state) && window_state(state))
440    eh->hide_windows();
441
442  int old_state=state;
443  state=new_state;
444
445  pal->load();    // restore old palette
446
447  if (playing_state(state) &&  !(dev&EDIT_MODE))
448    eh->set_mouse_shape(cash.img(c_target)->copy(),8,8);
449  else
450    eh->set_mouse_shape(cash.img(c_normal)->copy(),1,1);
451
452  if (old_state==SCENE_STATE && new_state!=SCENE_STATE)
453  {
454    d=1;
455    scene_director.set_abort(0);   // don't skip any more scene stuff
456  }
457  else if (new_state==SCENE_STATE && old_state!=SCENE_STATE)
458    d=1;
459 
460  if (d)
461    draw(state==SCENE_STATE);
462
463  dev_cont->set_state(new_state);
464}
465
466void game::joy_calb(event &ev)
467{
468  if (joy_win)   // make sure the joy stick calibration window is open
469  {
470   
471    if (ev.type==EV_SPURIOUS)   // spurious means we should update your status
472    {
473      int b1,b2,b3=0,x,y;
474      joy_status(b1,b2,b2,x,y);
475      int but=b1|b2|b3;
476      if (x>0) x=1; else if (x<0) x=-1;
477      if (y>0) y=1; else if (y<0) y=-1;
478      if (but) but=1;
479      int dx=WINDOW_FRAME_LEFT+20,dy=WINDOW_FRAME_TOP+5;
480      image *jim=cash.img(joy_picts[but*9+(y+1)*3+x+1]);
481      joy_win->screen->bar(dx,dy,dx+jim->width()+6,dy+jim->height()+6,eh->black());
482      jim->put_image(joy_win->screen,dx+3,dy+3);
483
484      if (but)
485        joy_calibrate();
486    } else if (ev.type==EV_MESSAGE && ev.message.id==JOY_OK)
487    {
488      eh->close_window(joy_win);
489      joy_win=NULL;
490      set_state(MENU_STATE);
491    }       
492  }
493}
494
495void game::menu_select(event &ev)
496{
497  state=DEV_MOUSE_RELEASE;
498  if (top_menu)
499  {
500/*    eh->push_event(new event(men_mess[((pick_list *)ev.message.data)->get_selection()],NULL));
501    eh->close_window(top_menu);
502    top_menu=NULL;*/
503  }
504}
505
506
507void game::show_help(char *st)
508{
509  strcpy(help_text,st);
510  help_text_frames=0; 
511  refresh=1;
512}
513
514void game::draw_value(image *screen, int x, int y, int w, int h, int val, int max)
515{
516  screen->bar(x,y,x+w-1,y+h,eh->dark_color());
517  screen->bar(x,y+1,x+w*val/max,y+h-1,eh->bright_color()); 
518}
519
520
521void game::set_level(level *nl)
522{
523  if (current_level)
524    delete current_level; 
525  current_level=nl;
526}
527
528void game::load_level(char *name)
529{
530  if (current_level)
531    delete current_level;
532
533  bFILE *fp=open_file(name,"rb");
534
535  if (fp->open_failure())
536  {
537    delete fp;
538    current_level=new level(100,100,name);
539    char msg[100];
540    sprintf(msg,symbol_str("no_file"),name);
541    show_help(msg);
542  }
543  else
544  {                           
545    spec_directory sd(fp); 
546
547#if 0
548    spec_entry *e=sd.find("Copyright 1995 Crack dot Com, All Rights reserved");
549    if (!e)
550    {
551      the_game->show_help(symbol_str("missing_c"));
552      current_level=new level(100,100,"untitled");
553      the_game->need_refresh();
554    }
555    else
556#endif
557      current_level=new level(&sd,fp,name);
558    delete fp;
559  }
560 
561  base->current_tick=(current_level->tick_counter()&0xff);
562
563  current_level->level_loaded_notify();
564  the_game->help_text_frames=0; 
565
566}
567
568int game::done()
569{
570  return finished || (main_net_cfg && main_net_cfg->restart_state());
571
572}
573
574void game::end_session()
575{
576  finished=1;
577  if (main_net_cfg)
578  {
579    delete main_net_cfg;
580    main_net_cfg=NULL;
581  }
582}
583
584void game::put_block_fg(int x, int y, trans_image *im)
585{
586  for (view *f=first_view;f;f=f->next)
587  {
588    if (f->drawable())
589    {
590      int xoff=f->xoff(),yoff=f->yoff(),viewx1=f->cx1,viewy1=f->cy1,viewx2=f->cx2,viewy2=f->cy2;
591      if (xoff/ftile_width()>x || xoff/ftile_width()+(viewx2-viewx1)/ftile_width()+1<x ||
592          yoff/ftile_height()>y || yoff/ftile_height()+(viewy2-viewy1)/ftile_height()+1<y) return;
593      short cx1,cy1,cx2,cy2;
594      screen->get_clip(cx1,cy1,cx2,cy2);
595      screen->set_clip(viewx1,viewy1,viewx2,viewy2);
596      im->put_image(screen,(x-xoff/ftile_width())*ftile_width()+viewx1-xoff%ftile_width(),
597                    (y-yoff/ftile_height())*ftile_height()+viewy1-yoff%ftile_height());
598      screen->set_clip(cx1,cy1,cx2,cy2);
599    }
600  }
601}
602
603void game::put_block_bg(int x, int y, image *im)
604{
605  for (view *f=first_view;f;f=f->next)
606  {
607    if (f->drawable())
608    {
609      int xoff=f->xoff(),yoff=f->yoff(),viewx1=f->cx1,viewy1=f->cy1,viewx2=f->cx2,viewy2=f->cy2;
610      int xo=xoff*bg_xmul/bg_xdiv;
611      int yo=yoff*bg_ymul/bg_ydiv;
612     
613      if (xo/btile_width()>x || xo/btile_width()+(viewx2-viewx1)/btile_width()+1<x ||
614          yo/btile_height()>y || yo/btile_height()+(viewy2-viewy1)/btile_height()+1<y) return;
615      short cx1,cy1,cx2,cy2;
616      screen->get_clip(cx1,cy1,cx2,cy2);
617      screen->set_clip(viewx1,viewy1,viewx2,viewy2);
618      im->put_image(screen,(x-xo/btile_width())*btile_width()+viewx1-xo%btile_width(),
619                    (y-yo/btile_height())*btile_height()+viewy1-yo%btile_height(),0);
620      screen->set_clip(cx1,cy1,cx2,cy2);
621    }
622  }
623}
624
625int need_delay=1;
626
627void game::dev_scroll()
628{
629  need_delay=0;
630  if (dev)
631  {
632    int xmargin,ymargin;
633    if (xres>400)
634    {
635      xmargin=20;
636      ymargin=10;
637    }
638    else
639    {
640      xmargin=10;
641      ymargin=5;
642    }
643
644    int xs,ys;
645    if (mousex<xmargin &&  dev_cont->ok_to_scroll()) xs=-18;
646    else if (mousex>(screen->width()-xmargin) &&  dev_cont->ok_to_scroll()) xs=18;
647    else if (eh->key_pressed(JK_LEFT) && !last_input && !dev_cont->need_arrows())
648      xs=-18;
649    else if (eh->key_pressed(JK_RIGHT) && !last_input && !dev_cont->need_arrows())
650      xs=18;
651    else xs=0;
652             
653
654    if (mousey<ymargin && dev_cont->ok_to_scroll()) ys=-18;
655    else if (mousey>(screen->height()-ymargin) &&  dev_cont->ok_to_scroll()) ys=18;
656    else if (eh->key_pressed(JK_UP) && !last_input)
657      ys=-18;
658    else if (eh->key_pressed(JK_DOWN) && !last_input)
659      ys=18;
660    else ys=0;
661
662   
663    if (xs || ys)
664    {
665      need_delay=1;
666      if (dev&MAP_MODE)
667      {
668        map_xoff+=xs/2;
669        map_yoff+=ys/2;
670        if (map_xoff<0) map_xoff=0;
671        if (map_yoff<0) map_yoff=0;
672      }
673      else
674      {
675        for (view *v=first_view;v;v=v->next)
676        {
677          if (xs>=0 || v->xoff()>0)
678            v->pan_x+=xs;
679          if (ys>=0 || v->yoff()>0)
680            v->pan_y+=ys;
681        }
682      }
683      refresh=1;
684    }
685  }
686}
687
688void remap_area(image *screen, int x1, int y1, int x2, int y2, uint8_t *remap)
689{
690  uint8_t *sl=(uint8_t *)screen->scan_line(y1)+x1;
691  int x,y,a=screen->width()-(x2-x1+1);
692  uint8_t c;
693  for (y=y1;y<=y2;y++)
694  {
695    for (x=x1;x<=x2;x++)
696    {
697      c=*sl;
698      *(sl++)=remap[c];
699    }
700    sl+=a;
701  }
702}
703
704void post_render()
705{
706  if (DEFINEDP(symbol_function(l_post_render)))
707  {
708    screen->dirt_off();
709    clear_tmp();
710    eval_function((lisp_symbol *)l_post_render,NULL);
711    clear_tmp();
712    screen->dirt_on();
713  }
714}
715 
716void game::draw_map(view *v, int interpolate)
717{
718  backtile *bt;
719  int x1,y1,x2,y2,x,y,xo,yo,nxoff,nyoff;
720  short cx1,cy1,cx2,cy2;
721  screen->get_clip(cx1,cy1,cx2,cy2);
722
723  if (!current_level || state==MENU_STATE)
724  {
725    if (title_screen>=0)
726    {
727      if (state==SCENE_STATE)
728        screen->set_clip(v->cx1,v->cy1,v->cx2,v->cy2);       
729      image *tit=cash.img(title_screen);
730      tit->put_image(screen,screen->width()/2-tit->width()/2,
731                            screen->height()/2-tit->height()/2);
732      if (state==SCENE_STATE)
733        screen->set_clip(cx1,cy1,cx2,cy2);
734      eh->flush_screen();
735    }   
736    return ;
737  }
738
739  refresh=0; 
740
741
742  // save the dirty rect routines some work by markinging evrything in the
743  // view area dirty alreadt
744
745  if (small_render)
746    screen->add_dirty(v->cx1,v->cy1,(v->cx2-v->cx1+1)*2+v->cx1,v->cy1+(v->cy2-v->cy1+1)*2);   
747  else
748    screen->add_dirty(v->cx1,v->cy1,v->cx2,v->cy2);   
749
750  if (v->draw_solid!=-1)      // fill the screen and exit..
751  {
752    int c=v->draw_solid;
753    for (int y=v->cy1;y<=v->cy2;y++)
754      memset(screen->scan_line(y)+v->cx1,c,v->cx2-v->cx1+1);
755    v->draw_solid=-1;
756    return ;
757  }
758
759  int32_t old_cx1=0,old_cy1=0,old_cx2=0,old_cy2=0;   // if we do a small render, we need to restore these
760  image *old_screen=NULL;
761  if (small_render && (dev&DRAW_LIGHTS))  // cannot do this if we skip lighting
762  {
763    old_cx1=v->cx1;
764    old_cy1=v->cy1;
765    old_cx2=v->cx2;
766    old_cy2=v->cy2;
767
768    v->cx1=0;
769    v->cy1=0;
770    v->cx2=small_render->width()-1;
771    v->cy2=small_render->height()-1;
772
773    old_screen=screen;
774    screen=small_render;
775  } else
776    screen->dirt_off();
777
778
779
780//  int32_t max_xoff=(current_level->foreground_width()-1)*ftile_width()-(v->cx2-v->cx1+1);
781//  int32_t max_yoff=(current_level->foreground_height()-1)*ftile_height()-(v->cy2-v->cy1+1);
782
783  int32_t xoff,yoff;
784  if (interpolate)
785  {
786    xoff=v->interpolated_xoff();
787    yoff=v->interpolated_yoff();
788  } else
789  {
790    xoff=v->xoff();
791    yoff=v->yoff();
792  }
793
794//  if (xoff>max_xoff) xoff=max_xoff;
795//  if (yoff>max_yoff) yoff=max_yoff; 
796
797  current_vxadd=xoff-v->cx1;
798  current_vyadd=yoff-v->cy1;
799
800  screen->set_clip(v->cx1,v->cy1,v->cx2,v->cy2);
801
802  nxoff=xoff*bg_xmul/bg_xdiv;
803  nyoff=yoff*bg_ymul/bg_ydiv;
804
805//  int32_t max_bg_xoff=(current_level->background_width())*btile_width()-(v->cx2-v->cx1+1);
806//  int32_t max_bg_yoff=(current_level->background_height())*btile_height()-(v->cy2-v->cy1+1);
807//  if (nxoff>max_bg_xoff) nxoff=max_xoff;
808//  if (nyoff>max_bg_yoff) nyoff=max_yoff; 
809 
810 
811  x1=nxoff/btile_width(); y1=nyoff/btile_height();
812  x2=x1+(v->cx2-v->cx1+btile_width())/btile_width();
813  y2=y1+(v->cy2-v->cy1+btile_height())/btile_height();
814
815
816  xo=v->cx1-nxoff%btile_width();
817  yo=v->cy1-nyoff%btile_height();
818 
819  int xinc,yinc,draw_x,draw_y;
820
821
822  if (!(dev & MAP_MODE) && (dev & DRAW_BG_LAYER))
823  {
824    xinc=btile_width(); 
825    yinc=btile_height(); 
826   
827    int bh=current_level->background_height(),bw=current_level->background_width();
828    uint16_t *bl;
829    for (draw_y=yo,y=y1;y<=y2;y++,draw_y+=yinc)
830    {
831      if (y>=bh)
832        bl=NULL;
833      else
834        bl=current_level->get_bgline(y)+x1;
835
836      for (x=x1,draw_x=xo;x<=x2;x++,draw_x+=xinc)
837      {
838        if (x<bw && y<bh)
839        {
840          bt=get_bg(*bl);
841          bl++;
842        }
843        else bt=get_bg(0);
844
845        bt->im->put_image(screen,draw_x,draw_y);
846//        if (!(dev & EDIT_MODE) && bt->next)
847//        current_level->put_bg(x,y,bt->next);
848      }
849    }
850  }
851
852//  if (!(dev&EDIT_MODE))
853//    server_check();
854
855  uint8_t rescan=0; 
856
857    int fw,fh;
858
859    if (dev&MAP_MODE)
860    {
861      fw=AUTOTILE_WIDTH;
862      fh=AUTOTILE_HEIGHT;
863      if (dev&EDIT_MODE)
864      {
865        x1=map_xoff;
866        y1=map_yoff;
867      } else
868      {
869        if (v->focus)
870        {
871          x1=v->focus->x/ftile_width()-(v->cx2-v->cx1)/fw/2;
872          y1=v->focus->y/ftile_height()-(v->cy2-v->cy1)/fh/2;
873        } else x1=y1=0;
874      }
875      if (x1>0)
876        xo=v->cx1-((v->focus->x*fw/ftile_width()) %fw);
877      else xo=v->cx1;
878      if (y1>0)
879        yo=v->cy1-((v->focus->y*fh/ftile_height()) %fh);
880      else yo=v->cy1;
881    } else
882    {
883      fw=ftile_width();
884      fh=ftile_height();
885      x1=(xoff)/fw; y1=(yoff)/fh;
886      xo=v->cx1-xoff%fw;
887      yo=v->cy1-yoff%fh;
888
889    }
890    if (x1<0) x1=0;
891    if (y1<0) y1=0;
892   
893    x2=x1+(v->cx2-v->cx1+fw)/fw;
894    y2=y1+(v->cy2-v->cy1+fh)/fh;
895    if (x2>=current_level->foreground_width())
896      x2=current_level->foreground_width()-1;
897    if (y2>=current_level->foreground_height())
898      y2=current_level->foreground_height()-1;
899
900
901    xinc=fw;
902    yinc=fh;
903
904  if (dev & DRAW_FG_LAYER)
905  {
906    short ncx1,ncy1,ncx2,ncy2;
907    screen->get_clip(ncx1,ncy1,ncx2,ncy2);
908
909    int scr_w=screen->width();
910    if (dev&MAP_MODE)
911    {
912      if (dev&EDIT_MODE)
913        screen->clear(eh->bright_color());
914      else
915        screen->clear(eh->black());
916      for (y=y1,draw_y=yo;y<=y2;y++,draw_y+=yinc)
917      {
918        if (!(draw_y<ncy1 ||draw_y+yinc>=ncy2))
919        {
920          uint16_t *cl=current_level->get_fgline(y)+x1;
921          uint8_t *sl1=screen->scan_line(draw_y)+xo;
922          for (x=x1,draw_x=xo;x<=x2;x++,cl++,sl1+=xinc,draw_x+=xinc)
923          {
924            if (!(draw_x<ncx1 || draw_x+xinc>=ncx2))
925            {
926              int fort_num;
927//            if (*cl&0x8000 || (dev&EDIT_MODE))
928                fort_num=fgvalue(*cl);
929//            else fort_num=0;
930
931              uint8_t *sl2=get_fg(fort_num)->micro_image->scan_line(0);
932              uint8_t *sl3=sl1;
933              memcpy(sl3,sl2,AUTOTILE_WIDTH); sl2+=AUTOTILE_WIDTH; sl3+=scr_w;
934              memcpy(sl3,sl2,AUTOTILE_WIDTH); sl2+=AUTOTILE_WIDTH; sl3+=scr_w;
935              memcpy(sl3,sl2,AUTOTILE_WIDTH);
936            }
937          }
938        }
939      }
940
941      if (dev&EDIT_MODE)
942        current_level->draw_areas(v);
943    } else
944    {
945
946      int fg_h=current_level->foreground_height(),fg_w=current_level->foreground_width();
947     
948      for (y=y1,draw_y=yo;y<=y2;y++,draw_y+=yinc)
949      {
950       
951        uint16_t *cl;
952        if (y<fg_h)
953          cl=current_level->get_fgline(y)+x1;
954        else cl=NULL;
955        uint8_t *sl1=draw_y<ncy1 ? 0 : screen->scan_line(draw_y)+xo;
956
957        for (x=x1,draw_x=xo;x<=x2;x++,draw_x+=xinc,cl++,sl1+=xinc)
958        {
959          if (x<fg_w && y<fg_h)
960          {
961            if (above_tile(*cl))
962            rescan=1;
963            else
964            {
965              int fort_num=fgvalue(*cl);         
966              if (fort_num!=BLACK)
967              {
968                if (draw_y<ncy1 || draw_y+yinc>=ncy2 || draw_x<ncx1 || draw_x+xinc>=ncx2)
969                get_fg(fort_num)->im->put_image(screen,draw_x,draw_y);
970                else
971                get_fg(fort_num)->im->put_image_offseted(screen,sl1);
972
973                if (!(dev & EDIT_MODE))
974                *cl|=0x8000;      // mark as has-been-seen
975              }
976            }
977          }
978        }
979      } 
980    }
981/*        if (dev==0)
982          current_level->put_fg(x,y,ft->next);  */       
983  }
984
985//  if (!(dev&EDIT_MODE))
986//    server_check();
987
988  int32_t ro=rand_on;
989  if (dev & DRAW_PEOPLE_LAYER)
990  {
991    if (interpolate)
992      current_level->interpolate_draw_objects(v);
993    else
994      current_level->draw_objects(v);
995  }
996
997//  if (!(dev&EDIT_MODE))
998//    server_check();
999
1000  if (!(dev&MAP_MODE))
1001  {
1002
1003    draw_panims(v);
1004
1005    if (dev & DRAW_FG_LAYER && rescan)
1006    {
1007      for (y=y1,draw_y=yo;y<=y2;y++,draw_y+=yinc)
1008      {
1009        uint16_t *cl=current_level->get_fgline(y)+x1;
1010        for (x=x1,draw_x=xo;x<=x2;x++,draw_x+=xinc,cl++)
1011        {
1012          if (above_tile(*cl))
1013          {
1014            int fort_num=fgvalue(*cl);   
1015            if (fort_num!=BLACK)
1016            {
1017              if (dev & DRAW_BG_LAYER)
1018              get_fg(fort_num)->im->put_image(screen,draw_x,draw_y);
1019              else
1020              get_fg(fort_num)->im->put_image_filled(screen,draw_x,draw_y,0);
1021
1022              if (!(dev & EDIT_MODE))
1023              current_level->mark_seen(x,y);
1024              else
1025              {
1026                screen->line(draw_x,draw_y,draw_x+xinc,draw_y+yinc,eh->bright_color());
1027                screen->line(draw_x+xinc,draw_y,draw_x,draw_y+yinc,eh->bright_color());
1028              }
1029            }   
1030          }
1031        }
1032      }   
1033    }
1034
1035   
1036    if (dev & DRAW_FG_BOUND_LAYER)
1037    {
1038      int b=eh->bright_color();
1039      int fg_h=current_level->foreground_height(),fg_w=current_level->foreground_width();
1040
1041      for (y=y1,draw_y=yo;y<=y2;y++,draw_y+=yinc)
1042      {
1043        uint16_t *cl;
1044        if (y<fg_h)
1045          cl=current_level->get_fgline(y)+x1;
1046        else cl=NULL;
1047        for (x=x1,draw_x=xo;x<=x2;x++,draw_x+=xinc,cl++)
1048        {
1049          if (x<fg_w && y<fg_h)
1050          {
1051            int fort_num=fgvalue(*cl);   
1052            if (fort_num!=BLACK)
1053            {
1054              point_list *p=get_fg(fort_num)->points;
1055              uint8_t *d=p->data;       
1056              if (p->tot)
1057              {
1058                for (int i=1;i<p->tot;i++)
1059                {
1060                  d+=2;
1061                  screen->line(draw_x+*(d-2),draw_y+*(d-1),draw_x+*d,draw_y+*(d+1),b);
1062                }
1063                screen->line(draw_x+*d,draw_y+*(d-1),draw_x+p->data[0],draw_y+p->data[1],b);
1064              }
1065            }
1066          }
1067        }
1068      }
1069    }
1070
1071//    if (!(dev&EDIT_MODE))
1072//      server_check();
1073
1074    if (dev & DRAW_HELP_LAYER)
1075    {
1076      if (help_text_frames>=0)
1077      {
1078        int color;
1079       
1080        if (help_text_frames<10)
1081        color=2;
1082        else
1083        color=2+(help_text_frames-10);
1084       
1085        int x1=v->cx1,y1=v->cy1,x2=v->cx2,y2=v->cy1+eh->font()->height()+10;
1086
1087        remap_area(screen,x1,y1,x2,y2,white_light+40*256);
1088        screen->bar(x1,y1,x2,y1,color);
1089        screen->bar(x1,y2,x2,y2,color);
1090
1091        eh->font()->put_string(screen,x1+5,y1+5,
1092                               help_text,color);
1093        if (color>30)
1094        help_text_frames=-1;     
1095        else help_text_frames++;
1096       
1097      }   
1098    }
1099   
1100    if (dev_cont)
1101    dev_cont->dev_draw(v); 
1102    if (cash.in_use())
1103    cash.img(vmm_image)->put_image(screen,v->cx1,v->cy2-cash.img(vmm_image)->height()+1); 
1104
1105    if (dev&DRAW_LIGHTS)
1106    { 
1107      if (small_render)
1108      {
1109        double_light_screen(screen,xoff,yoff,white_light,v->ambient,old_screen,old_cx1,old_cy1);
1110
1111        v->cx1=old_cx1;
1112        v->cy1=old_cy1;
1113        v->cx2=old_cx2;
1114        v->cy2=old_cy2;
1115        screen=old_screen;
1116      } else
1117      {     
1118        screen->dirt_on();
1119        if (xres*yres<=64000)
1120          light_screen(screen,xoff,yoff,white_light,v->ambient);
1121        else light_screen(screen,xoff,yoff,white_light,63);            // no lighting for hi-rez
1122      }
1123
1124    } else
1125      screen->dirt_on();
1126
1127
1128
1129  }  else
1130    screen->dirt_on();
1131
1132  rand_on=ro;                // restore random start in case in draw funs moved it
1133                               // ... not every machine will draw the same thing
1134
1135  post_render();
1136
1137  screen->set_clip(cx1,cy1,cx2,cy2);
1138   
1139
1140
1141
1142  if (playing_state(state))        // draw stuff outside the clipping region
1143    v->draw_character_damage();
1144
1145  if (profiling())
1146    profile_update();
1147
1148  sbar.draw_update();
1149}
1150
1151void game::put_fg(int x, int y, int type)
1152{
1153  if (current_level->get_fg(x,y)!=type)
1154  {
1155    current_level->put_fg(x,y,type);
1156    for (view *f=first_view;f;f=f->next)
1157      if (f->drawable())
1158        draw_map(f);   
1159/*    put_block_bg(x,y,get_bg(current_level->get_bg(x/ASPECT,y/ASPECT))->im);
1160    if (type>BLACK)
1161      put_block_fg(x,y,get_fg(type)->im); */
1162  }
1163}
1164
1165void game::put_bg(int x, int y, int type)
1166{
1167  if (current_level->get_bg(x,y)!=type)
1168  {
1169    current_level->put_bg(x,y,type);
1170    for (view *f=first_view;f;f=f->next)
1171      if (f->drawable())
1172        draw_map(f);   
1173/*    put_block_bg(x,y,get_bg(type)->im);
1174    if (current_level->get_fg(x,y)>BLACK)
1175      put_block_fg(x,y,get_fg(current_level->get_fg(x,y))->im);*/
1176  }
1177}
1178
1179int game::in_area(event &ev, int x1, int y1, int x2, int y2)
1180{
1181  return (last_demo_mx>=x1 && last_demo_mx<=x2 &&
1182          last_demo_my>=y1 && last_demo_my<=y2);
1183}
1184
1185void game::request_level_load(char *name)
1186{
1187  strcpy(req_name,name);
1188}
1189
1190extern int start_doubled;
1191
1192void fade_in(image *im, int steps)
1193{
1194  palette *old_pal=pal->copy();
1195  int i;
1196  if (im)
1197  {
1198    screen->clear();
1199    im->put_image(screen,(xres+1)/2-im->width()/2,(yres+1)/2-im->height()/2);
1200  }
1201
1202  for (i=0;i<steps;i++)
1203  {
1204    uint8_t *sl1=(uint8_t *)pal->addr();   
1205    uint8_t *sl2=(uint8_t *)old_pal->addr();   
1206    int j;
1207    int v=(i+1)*256/steps;
1208    for (j=0;j<256;j++)
1209    {
1210      *(sl1)=((int)*(sl2))*v/256;  sl1++; sl2++;
1211      *(sl1)=((int)*(sl2))*v/256;  sl1++; sl2++;
1212      *(sl1)=((int)*(sl2))*v/256;  sl1++; sl2++;
1213    }
1214    pal->load();
1215    eh->flush_screen();
1216    milli_wait(25);
1217  }
1218  delete pal;
1219  pal=old_pal;
1220}
1221
1222void fade_out(int steps)
1223{
1224  palette *old_pal=pal->copy();
1225  int i;
1226  for (i=0;i<steps;i++)
1227  {
1228    uint8_t *sl1=(uint8_t *)pal->addr();   
1229    uint8_t *sl2=(uint8_t *)old_pal->addr();   
1230    int j;
1231    int v=(steps-i)*256/steps;
1232    for (j=0;j<256;j++)
1233    {
1234      *(sl1)=((int)*(sl2))*v/256;  sl1++; sl2++;
1235      *(sl1)=((int)*(sl2))*v/256;  sl1++; sl2++;
1236      *(sl1)=((int)*(sl2))*v/256;  sl1++; sl2++;
1237    }
1238    pal->load();
1239    eh->flush_screen();
1240    milli_wait(25);
1241  }
1242  screen->clear();
1243  eh->flush_screen();
1244  delete pal;
1245  pal=old_pal;
1246 
1247  pal->load();
1248}
1249
1250int text_draw(int y, int x1, int y1, int x2, int y2, char *buf, JCFont *font, uint8_t *cmap, char color);
1251
1252void do_title()
1253{
1254        if( cdc_logo != -1 )
1255        {
1256                if( sound_avail & MUSIC_INITIALIZED )
1257                {
1258                        if( current_song )
1259                        {
1260                                current_song->stop();
1261                                delete current_song;
1262                        }
1263                        current_song=new song("music/intro.hmi");
1264                        current_song->play(music_volume);
1265                }
1266
1267                void *logo_snd = symbol_value( make_find_symbol( "LOGO_SND" ) );
1268
1269                if( DEFINEDP( logo_snd ) && ( sound_avail & SFX_INITIALIZED ) )
1270                        cash.sfx( lnumber_value( logo_snd ) )->play( sfx_volume );
1271
1272                image blank( 2, 2 );
1273                blank.clear();
1274                eh->set_mouse_shape( blank.copy(), 0, 0 );      // don't show mouse
1275                fade_in( cash.img( cdc_logo ), 32 );
1276
1277                milli_wait( 900 );
1278
1279                void *space_snd = symbol_value( make_find_symbol( "SPACE_SND" ) );
1280
1281                fade_out( 32 );
1282                milli_wait( 300 );
1283
1284                int i, abort = 0;
1285                char *str = lstring_value( eval( make_find_symbol( "plot_start" ) ) );
1286
1287                bFILE *fp = open_file( "art/smoke.spe", "rb" );
1288                if( !fp->open_failure() )
1289                {
1290                        spec_directory sd( fp );
1291                        palette *old_pal = pal;
1292                        pal = new palette( sd.find( SPEC_PALETTE ), fp );
1293                        pal->shift( 1 );
1294
1295                        image *gray = new image( sd.find( "gray_pict" ), fp );
1296                        image *smoke[5];
1297
1298                        char nm[20];
1299                        for( i = 0; i < 5; i++ )
1300                        {
1301                                sprintf( nm, "smoke%04d.pcx", i + 1 );
1302                                smoke[i] = new image( sd.find( nm ), fp );
1303                        }
1304
1305                        screen->clear();
1306                        pal->load();
1307
1308                        int dx = ( xres + 1 ) / 2 - gray->width() / 2, dy = ( yres + 1 ) / 2 - gray->height() / 2;
1309                        gray->put_image( screen, dx, dy );
1310                        smoke[0]->put_image( screen, dx + 24, dy + 5 );
1311
1312                        fade_in( NULL, 16 );
1313                        uint8_t cmap[32];
1314                        for( i = 0; i < 32; i++ )
1315                        cmap[i] = pal->find_closest( i * 256 / 32, i * 256 / 32, i * 256 / 32 );
1316
1317                        event ev;
1318                        ev.type=EV_SPURIOUS;
1319                        time_marker start;
1320
1321                        for( i = 0; i < 320 && ( ev.type != EV_KEY && ev.type != EV_MOUSE_BUTTON ); i++ )
1322                        {
1323                                gray->put_image( screen, dx, dy );
1324                                smoke[i % 5]->put_image( screen, dx + 24, dy + 5 );
1325                                text_draw( 205 - i, dx + 15, dy, dx + 320 - 15, dy + 199, str, eh->font(), cmap, eh->bright_color() );
1326                                eh->flush_screen();
1327                                time_marker now;
1328
1329                                while( now.diff_time( &start ) < 0.18 )
1330                                {
1331                                        milli_wait(20); // ECS - Added the wait, so CPU utilization stays low during the story
1332                                        now.get_time();
1333                                }
1334
1335                                start.get_time();
1336
1337                                while( eh->event_waiting() && ev.type != EV_KEY)
1338                                {
1339                                        eh->get_event(ev);
1340                                }
1341                                if( ( i % 5 ) == 0 && DEFINEDP( space_snd ) && ( sound_avail & SFX_INITIALIZED ) )
1342                                {
1343                                        cash.sfx( lnumber_value( space_snd ) )->play( sfx_volume * 90 / 127 );
1344                                }
1345                        }
1346
1347                        the_game->reset_keymap();
1348
1349                        fade_out(16);
1350
1351                        for( i = 0; i < 5; i++ )
1352                                delete smoke[i];
1353                        delete gray;
1354                        delete pal;
1355                        pal = old_pal;
1356                }
1357                delete fp;
1358
1359                for( i = 0; i < 100 && !abort; i++ )
1360                {
1361                }
1362
1363                if( title_screen >= 0 )
1364                        fade_in( cash.img( title_screen ), 32 );
1365
1366                eh->set_mouse_shape( cash.img( c_normal )->copy(), 1, 1 );
1367        }
1368}
1369
1370extern int start_edit;
1371
1372void game::request_end()
1373{
1374  req_end=1;
1375}
1376
1377extern void fast_load_start_recording(char *name);
1378extern void fast_load_stop_recording();
1379extern void fast_load_start_reloading(char *name);
1380extern void fast_load_stop_reloading();
1381
1382game::game(int argc, char **argv)
1383{
1384  int i;
1385  req_name[0]=0;
1386  bg_xmul=bg_ymul=1;
1387  bg_xdiv=bg_ydiv=8;
1388  last_input=NULL;
1389  current_automap=NULL;
1390  current_level=NULL;
1391  refresh=1; 
1392  the_game=this; 
1393  top_menu=joy_win=NULL;
1394  old_view=first_view=NULL;
1395  nplayers=1;
1396
1397  help_text_frames=0; 
1398  strcpy(help_text,"");
1399
1400 
1401  for (i=1;i<argc;i++)
1402    if (!strcmp(argv[i],"-no_delay"))
1403    {
1404      no_delay=1;
1405      dprintf("Frame delay off (-nodelay)\n");
1406    }
1407
1408 
1409  image_init(); 
1410  zoom=15; 
1411  no_delay=0;
1412
1413  if (get_option("-use_joy")) 
1414  {
1415    has_joystick=joy_init(argc,argv);
1416    dprintf("Joystick : ");
1417    if (has_joystick) dprintf("detected\n");
1418    else dprintf("not detected\n");
1419  }
1420  else has_joystick=0;
1421
1422//      ProfilerInit(collectDetailed, bestTimeBase, 2000, 200); //prof
1423        char *fastpath;
1424        fastpath = (char *)jmalloc( strlen( get_save_filename_prefix() ) + 12 + 1, "fastpath" );
1425        sprintf( fastpath, "%sfastload.dat", get_save_filename_prefix() );
1426        fast_load_start_recording( fastpath );
1427        load_data(argc,argv); 
1428        fast_load_stop_recording();
1429        jfree( fastpath );
1430//      ProfilerDump("\pabuse.prof");  //prof   
1431//      ProfilerTerm();
1432
1433  get_key_bindings();
1434
1435  reset_keymap();                   // we think all the keys are up right now
1436  finished=0;
1437
1438  calc_light_table(pal);
1439
1440  if (current_level==NULL && net_start())  // if we joined a net game get level from server
1441  {
1442    if (!request_server_entry())
1443    {
1444      exit(0);
1445    }
1446    net_reload();
1447//    load_level(NET_STARTFILE);
1448  }
1449
1450
1451  set_mode(19,argc,argv);
1452  if (get_option("-2") && (xres<639 || yres<399))
1453  {
1454    close_graphics();
1455    fprintf(stderr,"Resolution must be > 640x400 to use -2 option\n");   
1456    exit(0);
1457  }
1458  pal->load();
1459 
1460  recalc_local_view_space();   // now that we know what size the screen is...
1461
1462  dark_color=get_color(cash.img(window_colors)->pixel(2,0));
1463  bright_color=get_color(cash.img(window_colors)->pixel(0,0));
1464  med_color=get_color(cash.img(window_colors)->pixel(1,0));
1465
1466  morph_dark_color=get_color(cash.img(window_colors)->pixel(2,1));
1467  morph_bright_color=get_color(cash.img(window_colors)->pixel(0,1));
1468  morph_med_color=get_color(cash.img(window_colors)->pixel(1,1));
1469  morph_sel_frame_color=pal->find_closest(255,255,0);
1470  light_connection_color=morph_sel_frame_color;
1471
1472  if (NILP(symbol_value(l_default_font)))
1473  {
1474    printf("No font defined, set symbol default-font to an image name\n");
1475    exit(0);
1476  }
1477  int font_pict;
1478  if (big_font_pict!=-1)
1479  {
1480    if (small_font_pict!=-1)
1481    {
1482      if (xres/(start_doubled ? 2 : 1)>400)
1483      {
1484        font_pict=big_font_pict;
1485      }
1486      else font_pict=small_font_pict;
1487    } else font_pict=big_font_pict;
1488  } else font_pict=small_font_pict;
1489 
1490  if (console_font_pict==-1) console_font_pict=font_pict;
1491  game_font=new JCFont(cash.img(font_pict));
1492
1493  console_font=new JCFont(cash.img(console_font_pict));
1494
1495  eh=new window_manager(screen,pal,bright_color,
1496                                   med_color,
1497                                   dark_color,
1498                                   game_font); 
1499
1500  delete stat_man;  // move to a graphical status manager
1501  gui_status_manager *gstat=new gui_status_manager(eh);
1502  gstat->set_window_title("status");
1503  stat_man=gstat;
1504
1505
1506  chat=new chat_console(eh,console_font,50,6);
1507
1508  if (!eh->has_mouse())
1509  {
1510    close_graphics();
1511    image_uninit();
1512    printf("No mouse driver detected, please rectify.\n");
1513    exit(0);
1514  }
1515
1516
1517  gamma_correct(pal);
1518
1519  if (main_net_cfg==NULL || (main_net_cfg->state!=net_configuration::SERVER &&
1520                             main_net_cfg->state!=net_configuration::CLIENT))
1521  {
1522    if (!start_edit && !net_start())
1523      do_title();
1524  } else if (main_net_cfg && main_net_cfg->state==net_configuration::SERVER)
1525  {
1526    the_game->load_level(level_file);
1527    start_running=1;
1528  }
1529   
1530
1531  dev|= DRAW_FG_LAYER | DRAW_BG_LAYER | DRAW_PEOPLE_LAYER | DRAW_HELP_LAYER | DRAW_LIGHTS | DRAW_LINKS;
1532
1533  if (dev & EDIT_MODE)
1534    set_frame_size(0);
1535//  do_intro();
1536  state=START_STATE;         // first set the state to one that has windows
1537
1538
1539  if (start_running)
1540    set_state(RUN_STATE);
1541  else
1542  {
1543    screen->clear(); 
1544    if (title_screen>=0)
1545    {
1546      image *tit=cash.img(title_screen);
1547      tit->put_image(screen,screen->width()/2-tit->width()/2,
1548                            screen->height()/2-tit->height()/2);
1549    }   
1550    set_state(MENU_STATE);   // then go to menu state so windows will turn off
1551  }
1552}
1553
1554
1555
1556time_marker *led_last_time=NULL,*fps_mark_start=NULL;
1557double avg_fps=15.0,possible_fps=15.0;
1558
1559void game::toggle_delay()
1560{
1561  no_delay=!no_delay;
1562  if (no_delay)
1563    show_help(symbol_str("delay_off"));
1564  else show_help(symbol_str("delay_on"));
1565  avg_fps=possible_fps=15.0;
1566}
1567
1568void game::show_time()
1569{
1570  if (first_view && fps_on)
1571  {
1572    char str[10];
1573    sprintf(str,"%ld",(long)(avg_fps*10.0));
1574    console_font->put_string(screen,first_view->cx1,first_view->cy1,str);
1575
1576    sprintf(str,"%d",total_active);
1577    console_font->put_string(screen,first_view->cx1,first_view->cy1+10,str);
1578  }
1579}
1580
1581void game::update_screen()
1582{
1583  if (state==HELP_STATE)
1584    draw_help();
1585  else if (current_level)
1586  {   
1587    if (!(dev & EDIT_MODE) || refresh)   
1588    {   
1589      view *f=first_view;
1590      current_level->clear_active_list();
1591      for (;f;f=f->next)
1592      {
1593        if (f->focus)           
1594        {
1595          int w,h;
1596
1597          w=(f->cx2-f->cx1+1);
1598          h=(f->cy2-f->cy1+1);
1599
1600          total_active+=current_level->add_drawables(f->xoff()-w/4,f->yoff()-h/4,
1601                                                     f->xoff()+w+w/4,f->yoff()+h+h/4);
1602
1603        }
1604      }
1605
1606      for (f=first_view;f;f=f->next)
1607      {
1608        if (f->drawable())
1609        {
1610          if (interpolate_draw)
1611          {
1612            draw_map(f,1);
1613            eh->flush_screen();
1614          }
1615          draw_map(f,0);
1616        }
1617      }
1618      if (current_automap)
1619      current_automap->draw();
1620    } 
1621    if (state==PAUSE_STATE)
1622    {
1623      for (view *f=first_view;f;f=f->next)
1624        cash.img(pause_image)->put_image(screen,(f->cx1+f->cx2)/2-cash.img(pause_image)->width()/2,
1625                               f->cy1+5,1);
1626    }
1627   
1628    show_time();
1629  }
1630
1631  if (state==RUN_STATE && cash.prof_is_on())
1632    cash.prof_poll_end();
1633
1634  eh->flush_screen();
1635
1636}
1637
1638void game::do_intro()
1639{
1640
1641}
1642
1643int game::calc_speed()
1644{
1645        int ret=0;
1646        if( fps_mark_start )
1647        {
1648                time_marker t;
1649
1650                // find average fps for last 10 frames
1651                double td=t.diff_time(fps_mark_start);
1652                if (td<0.001)     // something is rotten in the state of demark
1653                        td=0.001;
1654
1655                avg_fps=avg_fps*9.0/10.0+1.0/(td*10.0); 
1656                possible_fps=possible_fps*9.0/10.0+1.0/(td*10.0); 
1657
1658                if (avg_fps>14)
1659                {
1660                        if (massive_frame_panic>20)
1661                                massive_frame_panic=20;
1662                        else if (massive_frame_panic)
1663                                massive_frame_panic--;
1664                }
1665
1666                if (avg_fps>15 && ((dev&EDIT_MODE)==0 || need_delay))
1667                {
1668                        frame_panic = 0;
1669                        int32_t stime=(int32_t)((1/15.0-1.0/possible_fps)*1000.0);
1670                        if (stime>0 && !no_delay)
1671                        {
1672                                milli_wait(stime);
1673                                avg_fps-=1.0/(td*10.0);   // subtract out old estimate
1674
1675                                time_marker t;
1676
1677                                // find average fps for last 10 frames
1678                                double td=t.diff_time(fps_mark_start);
1679                                if (td<0.00001)     // something is rotten in the state of demark
1680                                        td=0.00001;
1681
1682                                avg_fps+=1.0/(td*10.0);       // add in new estimate
1683                        }
1684                }
1685                else if (avg_fps<14)
1686                {
1687                        if (avg_fps<10)
1688                                massive_frame_panic++;
1689                        frame_panic++;
1690                        ret=1;
1691                }
1692                else if( dev & EDIT_MODE )
1693                {
1694                        // ECS - Added this case and the wait.  It's a cheap hack to assure that
1695                        // we don't exceed 30FPS in edit mode and hog the CPU.
1696                        milli_wait(33);
1697                }
1698
1699                delete fps_mark_start;   
1700        }
1701        fps_mark_start=new time_marker;
1702        return ret;
1703}
1704
1705extern int start_edit;
1706
1707void single_render();
1708void double_render();
1709
1710void game::get_input()
1711{
1712        event ev;
1713        idle_ticks++;
1714        while( event_waiting( eh ) )
1715        {
1716                get_event(ev,eh);
1717
1718                if(ev.type == EV_MOUSE_MOVE )
1719                {
1720                        last_input = ev.window;
1721                }
1722                // don't process repeated keys in the main window, it will slow down the game to handle such
1723                // useless events. However in other windows it might be useful, such as in input windows
1724                // where you want to repeatedly scroll down...
1725                if( ev.type != EV_KEY || !key_down( ev.key ) || ev.window || ( dev & EDIT_MODE ) )
1726                {
1727                        if( ev.type == EV_KEY )
1728                        {
1729                                set_key_down( ev.key, 1 );
1730                                if( playing_state( state ) )
1731                                {
1732                                        if(ev.key < 256 )
1733                                        {
1734                                                if( chat && chat->chat_event( ev ) )
1735                                                        base->packet.write_uint8( SCMD_CHAT_KEYPRESS );
1736                                                else
1737                                                        base->packet.write_uint8( SCMD_KEYPRESS );
1738                                        }
1739                                        else
1740                                                base->packet.write_uint8( SCMD_EXT_KEYPRESS );
1741                                        base->packet.write_uint8( client_number() );
1742                                        if( ev.key > 256 )
1743                                                base->packet.write_uint8( ev.key - 256 );
1744                                        else
1745                                                base->packet.write_uint8( ev.key );
1746                                }
1747                        }
1748                        else if(ev.type == EV_KEYRELEASE )
1749                        {
1750                                set_key_down( ev.key, 0 );
1751                                if( playing_state( state ) )
1752                                {
1753                                        if( ev.key < 256 )
1754                                                base->packet.write_uint8( SCMD_KEYRELEASE );
1755                                        else
1756                                                base->packet.write_uint8( SCMD_EXT_KEYRELEASE );
1757                                        base->packet.write_uint8( client_number() );
1758                                        if( ev.key > 255 )
1759                                                base->packet.write_uint8( ev.key - 256 );
1760                                        else
1761                                                base->packet.write_uint8( ev.key );
1762                                }
1763                        }
1764
1765                        if( (dev & EDIT_MODE) || start_edit || ev.type == EV_MESSAGE )
1766                        {
1767                                dev_cont->handle_event( ev );
1768                        }
1769
1770                        view *v = first_view;
1771                        for( ; v; v = v->next )
1772                        {
1773                                if( v->local_player() && v->handle_event( ev ) )
1774                                        ev.type=EV_SPURIOUS;       // if the event was used by the view, gobble it up
1775                        }
1776
1777                        if( current_automap )
1778                        {
1779                                current_automap->handle_event( ev );
1780                        }
1781
1782                        help_handle_event( ev );
1783                        mousex = last_demo_mx;
1784                        mousey = last_demo_my;
1785
1786                        if(ev.type == EV_MESSAGE )
1787                        {
1788                                switch (ev.message.id)
1789                                {
1790                                        case CALB_JOY:
1791                                        {
1792                                                if (!joy_win)
1793                                                {
1794                                                        int wx=WINDOW_FRAME_LEFT,wy=WINDOW_FRAME_TOP;
1795
1796                                                        joy_win=eh->new_window(80,50,-1,-1,
1797                                                                        new button(wx+70,wy+9,JOY_OK,"OK",
1798                                                                        new info_field(wx,wy+30,DEV_NULL,
1799                                                                        " Center joystick and\n"
1800                                                                        "press the fire button",NULL)),
1801                                                                        "Joystick");
1802                                                        set_state(JOY_CALB_STATE);
1803                                                }
1804                                        }
1805                                        case TOP_MENU:
1806                                        {
1807                                                menu_select(ev);
1808                                        } break;
1809                                        case DEV_QUIT:
1810                                        {
1811                                                finished = 1;
1812                                        } break;
1813                                }
1814                        }
1815                        else if(ev.type == EV_CLOSE_WINDOW && ev.window == top_menu )
1816                        {
1817                                eh->close_window( top_menu );
1818                                top_menu = NULL;
1819                        }
1820
1821                        switch( state )
1822                        {
1823                                case JOY_CALB_STATE:
1824                                {
1825                                        joy_calb(ev);
1826                                } break;
1827                                case INTRO_START_STATE:
1828                                {
1829                                        do_intro();
1830                                        if (dev & EDIT_MODE)
1831                                                set_state(RUN_STATE);
1832                                        else
1833                                                set_state(MENU_STATE);
1834                                } break;
1835                                case PAUSE_STATE:
1836                                {
1837                                        if( ev.type == EV_KEY && ( ev.key == JK_SPACE || ev.key == JK_ENTER ) )
1838                                        {
1839                                                set_state( RUN_STATE );
1840                                        }
1841                                } break;
1842                                case RUN_STATE:
1843                                {
1844                                        if (ev.window==NULL)
1845                                        {
1846                                                switch (ev.type)
1847                                                {
1848                                                        case EV_KEY:
1849                                                        {
1850                                                                switch (ev.key)
1851                                                                {
1852                                                                        case 'm':
1853                                                                        {
1854                                                                                if( dev & MAP_MODE )
1855                                                                                        dev -= MAP_MODE;
1856                                                                                else if( ( player_list && player_list->next ) || dev & EDIT_MODE )
1857                                                                                        dev |= MAP_MODE;
1858
1859                                                                                if( !( dev & MAP_MODE ) )
1860                                                                                {
1861                                                                                        if( dev_cont->tbw )
1862                                                                                                dev_cont->toggle_toolbar();
1863                                                                                        edit_mode = ID_DMODE_DRAW;
1864                                                                                }
1865                                                                                need_refresh();
1866                                                                        } break;
1867                                                                        case 'v':
1868                                                                        {
1869                                                                                eh->push_event(new event(DO_VOLUME,NULL));
1870                                                                        } break;
1871                                                                        case 'p':
1872                                                                        {
1873                                                                                if (!(dev&EDIT_MODE) && (!main_net_cfg ||
1874                                                                                        (main_net_cfg->state!=net_configuration::SERVER &&
1875                                                                                        main_net_cfg->state!=net_configuration::CLIENT)))
1876                                                                                {
1877                                                                                        set_state(PAUSE_STATE);
1878                                                                                }
1879                                                                        } break;
1880                                                                        case 'S':
1881                                                                        {
1882                                                                                if( start_edit )
1883                                                                                {
1884                                                                                        eh->push_event(new event(ID_LEVEL_SAVE,NULL));
1885                                                                                }
1886                                                                        } break;
1887                                                                        case JK_TAB:
1888                                                                        {
1889                                                                                if( start_edit )
1890                                                                                        toggle_edit_mode();
1891                                                                                need_refresh();
1892                                                                        } break;
1893                                                                        case 'c':
1894                                                                        {
1895                                                                                if( chatting_enabled && (!(dev&EDIT_MODE) && chat))
1896                                                                                        chat->toggle();
1897                                                                        } break;
1898                                                                        case '9':
1899                                                                        {
1900                                                                                dev = dev^PERFORMANCE_TEST_MODE;
1901                                                                                need_refresh();
1902                                                                        } break;
1903/*                                                                      case '=':
1904                                                                        case '+':
1905                                                                        {
1906                                                                                if (!dev_cont->need_plus_minus())
1907                                                                                {
1908                                                                                        if (eh->key_pressed(JK_CTRL_L))
1909                                                                                                grow_views(20);
1910                                                                                        else
1911                                                                                                grow_views(5);
1912                                                                                        draw(state==SCENE_STATE);
1913                                                                                }
1914                                                                        } break;
1915                                                                        case JK_F10:
1916                                                                        {
1917                                                                                make_screen_size(311,160);
1918                                                                        } break;
1919                                                                        case '_':
1920                                                                        case '-' :
1921                                                                        {
1922                                                                                if (!dev_cont->need_plus_minus())
1923                                                                                {
1924                                                                                        if (eh->key_pressed(JK_CTRL_L))
1925                                                                                                grow_views(-20);
1926                                                                                        else
1927                                                                                                grow_views(-5);
1928                                                                                        draw(state==SCENE_STATE);
1929                                                                                }
1930                                                                        } break;
1931*/
1932                                                                }
1933                                                        } break;
1934                                                        case EV_RESIZE:
1935                                                        {
1936                                                                view *v;
1937                                                                for( v = first_view; v; v = v->next )  // see if any views need to change size
1938                                                                {
1939                                                                        if (v->local_player())
1940                                                                        {
1941                                                                                int w = (xres-10)/(small_render ? 2 : 1);
1942                                                                                int h = (yres-10)/(small_render ? 2 : 1);
1943
1944                                                                                v->suggest.send_view = 1;
1945                                                                                v->suggest.cx1 = 5;
1946                                                                                v->suggest.cx2 = 5 + w;
1947                                                                                v->suggest.cy1 = 5;
1948                                                                                v->suggest.cy2 = 5 + h;
1949                                                                                v->suggest.pan_x = v->pan_x;
1950                                                                                v->suggest.pan_y = v->pan_y;
1951                                                                                v->suggest.shift_down = v->shift_down;
1952                                                                                v->suggest.shift_right = v->shift_right;
1953                                                                        }
1954                                                                }
1955                                                                draw();
1956                                                        } break;
1957                                                        case EV_REDRAW:
1958                                                        {
1959                                                                screen->add_dirty(ev.redraw.x1,ev.redraw.y1,
1960                                                                        ev.redraw.x2,ev.redraw.y2);
1961                                                        } break;
1962                                                        case EV_MESSAGE:
1963                                                        {
1964                                                                switch (ev.message.id)
1965                                                                {
1966                                                                        case RAISE_SFX:
1967                                                                        case LOWER_SFX:
1968                                                                        case RAISE_MUSIC:
1969                                                                        case LOWER_MUSIC:
1970                                                                        {
1971                                                                                if( ev.message.id == RAISE_SFX && sfx_volume != 127 )
1972                                                                                        sfx_volume = min( 127, sfx_volume + 16 );
1973                                                                                if( ev.message.id == LOWER_SFX && sfx_volume != 0 )
1974                                                                                        sfx_volume = max( sfx_volume - 16,0 );
1975                                                                                if( ev.message.id == RAISE_MUSIC && music_volume != 126 )
1976                                                                                {
1977                                                                                        music_volume = min( music_volume + 16, 127 );
1978                                                                                        if( current_song && ( sound_avail & MUSIC_INITIALIZED ) )
1979                                                                                                current_song->set_volume( music_volume );
1980                                                                                }
1981
1982                                                                                if( ev.message.id == LOWER_MUSIC && music_volume != 0 )
1983                                                                                {
1984                                                                                        music_volume = max( music_volume - 16, 0 );
1985                                                                                        if( current_song && (sound_avail & MUSIC_INITIALIZED ) )
1986                                                                                                current_song->set_volume( music_volume );
1987                                                                                }
1988
1989                                                                                ((button *)ev.message.data)->push();
1990/*                                                                              volume_window->inm->redraw();
1991                                                                                draw_value(volume_window->screen,WINDOW_FRAME_LEFT+2,WINDOW_FRAME_TOP+43,
1992                                                                                                (volume_window->x2()-volume_window->x1()-1),8, sfx_volume,127);
1993                                                                                draw_value(volume_window->screen,WINDOW_FRAME_LEFT+2,WINDOW_FRAME_TOP+94,
1994                                                                                                (volume_window->x2()-volume_window->x1()-1),8, music_volume,127);
1995*/
1996                                                                                break;
1997                                                                        }
1998                                                                }
1999                                                        }
2000                                                }
2001                                        }
2002                                } break;
2003                        }
2004                }
2005        }
2006}
2007
2008
2009void net_send(int force=0)
2010{
2011  if ( (!(dev&EDIT_MODE)) || force)
2012  {
2013    if (demo_man.state==demo_manager::PLAYING)
2014    {
2015      base->input_state=INPUT_PROCESSING;
2016    } else
2017    {
2018     
2019
2020
2021      if (!player_list->focus)
2022      {
2023        dprintf("Players have not been created\ncall create_players");
2024        exit(0);
2025      }
2026
2027
2028      view *p=player_list;
2029      for (;p;p=p->next)
2030        if (p->local_player())
2031          p->get_input();
2032
2033
2034      base->packet.write_uint8(SCMD_SYNC);
2035      base->packet.write_uint16(make_sync());
2036
2037      if (base->join_list)
2038      base->packet.write_uint8(SCMD_RELOAD);
2039
2040      //      printf("save tick %d, pk size=%d, rand_on=%d, sync=%d\n",current_level->tick_counter(),
2041      //             base->packet.packet_size(),rand_on,make_sync());
2042      send_local_request();
2043    }
2044  }
2045}
2046
2047void net_receive()
2048{
2049  if (!(dev&EDIT_MODE) && current_level)
2050  {
2051    uint8_t buf[PACKET_MAX_SIZE+1];
2052    int size;
2053
2054    if (demo_man.state==demo_manager::PLAYING)
2055    {
2056      if (!demo_man.get_packet(buf,size))
2057        size=0;
2058      base->packet.packet_reset();
2059      base->mem_lock=0;
2060    } else
2061    {
2062      size=get_inputs_from_server(buf);
2063      if (demo_man.state==demo_manager::RECORDING)
2064        demo_man.save_packet(buf,size);
2065    }
2066
2067    process_packet_commands(buf,size);
2068  }
2069}
2070
2071void game::step()
2072{
2073  clear_tmp();
2074  if (current_level)
2075  {
2076    current_level->unactivate_all();
2077    total_active=0;
2078    for (view *f=first_view;f;f=f->next)
2079    {
2080      if (f->focus)           
2081      {
2082        f->update_scroll();
2083        int w,h;
2084
2085        w=(f->cx2-f->cx1+1);
2086        h=(f->cy2-f->cy1+1);
2087        total_active+=current_level->add_actives(f->xoff()-w/4,f->yoff()-h/4,
2088                                                 f->xoff()+w+w/4,f->yoff()+h+h/4);
2089      }
2090    }
2091  }
2092
2093  if (state==RUN_STATE)
2094  {   
2095    if ((dev&EDIT_MODE) || (main_net_cfg && (main_net_cfg->state==net_configuration::CLIENT ||
2096                                             main_net_cfg->state==net_configuration::SERVER)))
2097      idle_ticks=0;
2098
2099    if (demo_man.current_state()==demo_manager::NORMAL && idle_ticks>420 && demo_start)
2100    {
2101      idle_ticks=0;
2102      set_state(MENU_STATE);   
2103    }
2104    else if (!(dev & EDIT_MODE))               // if edit mode, then don't step anything
2105    {
2106      if (key_down(JK_ESC))
2107      {
2108        set_state(MENU_STATE);
2109        set_key_down(JK_ESC,0);
2110      }
2111      ambient_ramp=0;
2112      view *v;
2113      for (v=first_view;v;v=v->next)
2114        v->update_scroll();
2115
2116      cash.prof_poll_start();
2117      current_level->tick();
2118      sbar.step();
2119    } else   
2120      dev_scroll(); 
2121  } else if (state==JOY_CALB_STATE)
2122  {
2123    event ev;
2124    joy_calb(ev);
2125  } else if (state==MENU_STATE) 
2126    main_menu(); 
2127   
2128  if (key_down('x') && (key_down(JK_ALT_L) || key_down(JK_ALT_R)) && confirm_quit()) finished=1;
2129}
2130
2131extern void *current_demo;
2132
2133game::~game()
2134{
2135  current_demo=NULL;
2136  if (first_view==player_list) first_view=NULL;
2137  while (player_list)
2138  {
2139    view *p=player_list;
2140    game_object *o=p->focus;
2141    player_list=player_list->next;
2142    delete p;
2143    o->set_controller(NULL);
2144    if (current_level && o)
2145      current_level->delete_object(o);
2146    else delete o;
2147  }
2148
2149  if (current_level) { delete current_level; current_level=NULL; }
2150
2151  if (first_view!=player_list)
2152  {
2153    while (player_list)
2154    {
2155      view *p=player_list;
2156      player_list=player_list->next;
2157      delete p;
2158    }
2159  }
2160
2161  while (first_view)
2162  {
2163    view *p=first_view;
2164    first_view=first_view->next;
2165    delete p;
2166  }
2167
2168  player_list=NULL; 
2169
2170  if (old_view)
2171  {
2172    first_view=old_view;
2173    while (first_view)
2174    {
2175      view *p=first_view;
2176      first_view=first_view->next;
2177      delete p;
2178    }
2179  }
2180  old_view=NULL;
2181
2182  int i=0;
2183  for (;i<total_objects;i++)
2184  {
2185    jfree(object_names[i]);
2186    delete figures[i];
2187  }
2188  free_pframes();
2189  if (fps_mark_start) delete fps_mark_start; fps_mark_start=NULL;
2190  delete pal;
2191  jfree(object_names);
2192  jfree(figures);
2193
2194  jfree(backtiles);
2195  jfree(foretiles);
2196  if (total_weapons)
2197    jfree(weapon_types);
2198
2199  config_cleanup();
2200  delete color_table;
2201  delete eh;
2202  delete game_font;
2203  delete big_font;
2204  delete console_font;
2205  if (total_help_screens)
2206    jfree(help_screens);
2207   
2208  close_graphics();
2209  image_uninit();
2210}
2211
2212
2213
2214void game::draw(int scene_mode)
2215{
2216        screen->add_dirty( 0, 0, xres, yres );
2217//      image *bt=cash.img(border_tile);
2218//      int tw=bt->width(),th=bt->height();
2219  screen->clear();
2220//  for (y=0;y<yt;y++,dy+=th)
2221//    for (x=0,dx=0;x<xt;x++,dx+=tw)
2222//      bt->put_image(screen,dx,dy);
2223
2224        if( scene_mode )
2225        {
2226                char *helpstr = "ARROW KEYS CHANGE TEXT SPEED";
2227                eh->font()->put_string(screen,screen->width()/2-(eh->font()->width()*strlen(helpstr))/2+1,
2228                        screen->height()-eh->font()->height()-5+1,helpstr,eh->dark_color());
2229                eh->font()->put_string(screen,screen->width()/2-(eh->font()->width()*strlen(helpstr))/2,
2230                        screen->height()-eh->font()->height()-5,helpstr,eh->bright_color());   
2231        }
2232/*      else
2233        {
2234                char *helpstr="PRESS h FOR HELP";
2235                eh->font()->put_string(screen,screen->width()-eh->font()->width()*strlen(helpstr)-5,
2236                        screen->height()-eh->font()->height()-5,helpstr);
2237        }*/
2238/*      int dc=cash.img(window_colors)->pixel(0,2);
2239        int mc=cash.img(window_colors)->pixel(1,2);
2240        int bc=cash.img(window_colors)->pixel(2,2);
2241        screen->line(0,0,screen->width()-1,0,dc);
2242        screen->line(0,0,0,screen->height()-1,dc);
2243        screen->line(0,screen->height()-1,screen->width()-1,screen->height()-1,bc);
2244        screen->line(screen->width()-1,0,screen->width()-1,screen->height()-1,bc); */
2245
2246        for( view *f = first_view; f; f = f->next )
2247                draw_map( f, 0 );
2248
2249        sbar.redraw( screen );
2250}
2251
2252int external_print=0;
2253
2254void start_sound(int argc, char **argv)
2255{
2256  sfx_volume=music_volume=127;
2257
2258  for (int i=1;i<argc;i++)
2259    if (!strcmp(argv[i],"-sfx_volume"))
2260    {
2261      i++;
2262      if (atoi(argv[i])>=0 && atoi(argv[i])<127)
2263        sfx_volume=atoi(argv[i]);
2264      else printf("Bad sound effects volume level, use 0..127\n");     
2265    }
2266    else if (!strcmp(argv[i],"-music_volume"))
2267    {
2268      i++;
2269      if (atoi(argv[i])>=0 && atoi(argv[i])<127)
2270        music_volume=atoi(argv[i]);
2271      else printf("Bad music volume level, use 0..127\n");     
2272    }
2273
2274  sound_avail=sound_init(argc,argv);
2275}
2276
2277void game_printer(char *st)
2278{
2279  if (dev_console && !external_print)
2280  {
2281    dev_console->put_string(st);
2282  }
2283  else fprintf(stderr,"%s",st);
2284}
2285
2286
2287void game_getter(char *st, int max)
2288{
2289  if (!max) return ;
2290  max--;
2291  *st=0;
2292  if (dev_console && !external_print)
2293  {   
2294    dev_console->show();
2295    int t=0;
2296    event ev;
2297    do
2298    {
2299      get_event(ev,eh);
2300      if (ev.type==EV_KEY)
2301      {
2302        if (ev.key==JK_BACKSPACE)
2303        {
2304          if (t)
2305          {
2306            dev_console->print_f("%c",ev.key);
2307            t--;
2308            st--;
2309            *st=0;
2310            max++;
2311          }
2312        } else if (ev.key>=' ' && ev.key<='~')
2313        {
2314          dev_console->print_f("%c",ev.key);
2315          *st=ev.key;
2316          t++;
2317          max--;
2318          st++;
2319          *st=0;
2320        }                         
2321      }
2322      eh->flush_screen();
2323    } while (ev.type!=EV_KEY || ev.key!=JK_ENTER);   
2324    dprintf("\n");
2325  }
2326  else
2327  {
2328    if (fgets(st,max,stdin))
2329    {
2330      if (*st)
2331        st[strlen(st)-1]=0;
2332    }
2333  }
2334}
2335
2336
2337void show_startup()
2338{
2339  show_verinfo(start_argc,start_argv);
2340}
2341
2342char *get_line(int open_braces)
2343{
2344  char *line=(char *)jmalloc(1000,"lstring");
2345  fgets(line,1000,stdin);
2346
2347  char prev=' ';
2348  for (char *s=line;*s && (prev!=' ' || *s!=';');s++)
2349  {
2350    prev=*s;
2351    if (*s=='(') open_braces++;
2352    else if (*s==')') open_braces--;
2353  }
2354  if (open_braces<0)   
2355    fprintf(stderr,"\nToo many )'s\n");
2356  else if (open_braces>0)
2357  {
2358    char *s2=get_line(open_braces);
2359    line=(char *)jrealloc(line,strlen(line)+strlen(s2)+1,"lstring");
2360    strcat(line,s2);
2361    jfree(s2);   
2362  } 
2363  return line;
2364}
2365
2366void check_for_upgrade(int argc, char **argv)
2367{
2368  for (int i=1;i<argc;i++)
2369    if (!strcmp(argv[i],"-upgrade"))
2370    {
2371      lisp_init(0xf000,0x30000);
2372      char *prog="(load \"lisp/upgrade.lsp\")",*cs;
2373      cs=prog;
2374      if (!eval(compile(cs)))
2375        printf("file does not exists : lisp/upgrade.lsp, cannot upgrade\n");
2376
2377      exit(0);
2378    }       
2379}
2380
2381void check_for_lisp(int argc, char **argv)
2382{
2383        for( int i = 1; i < argc; i++ )
2384        {
2385                if( !strcmp( argv[i], "-lisp" ) )
2386                {
2387                        lisp_init(0xf000,0x30000);
2388                        char *eof_char = "CTRL-D";
2389                        fprintf(stderr,
2390                                        " CLIVE (C) 1995 Jonathan Clark, all rights reserved\n"
2391                                        "   (C LISP interpreter and various extentions)\n"
2392                                        "Type (%s) to exit\n",eof_char);
2393
2394                        while (!feof(stdin))
2395                        {
2396                                fprintf(stderr,"Lisp> ");
2397                                char *l=get_line(0);
2398                                char *s=l;
2399                                while (*s)
2400                                {
2401                                        void *prog=compile(s);
2402                                        l_user_stack.push(prog);
2403                                        while (*s==' ' || *s=='\t' || *s=='\r' || *s=='\n') s++;
2404                                        lprint(eval(prog));
2405                                        l_user_stack.pop(1);
2406                                }
2407                                jfree(l);
2408                        }
2409                        fprintf(stderr,"End of input : bye\n");
2410                        exit(0);
2411                }
2412        }
2413}
2414
2415
2416void music_check()
2417{
2418  if (sound_avail&MUSIC_INITIALIZED)
2419  {
2420    if (current_song && !current_song->playing())
2421    {
2422      current_song->play();
2423      dprintf("song finished\n");
2424    }
2425    if (!current_song)
2426    {
2427
2428      current_song=new song("music/intro.hmi");
2429      current_song->play(music_volume);
2430
2431/*      if (DEFINEDP(symbol_function(l_next_song)))  // if user function installed, call it to load up next song
2432      {
2433        int sp=current_space;
2434        current_space=PERM_SPACE;
2435        eval_function((lisp_symbol *)l_next_song,NULL);
2436        current_space=sp;
2437      } */
2438    }
2439  }
2440}
2441
2442void setup(int argc, char **argv);
2443
2444void share_end();
2445void show_end();
2446
2447void show_sell(int abortable);
2448
2449extern pmenu *dev_menu;
2450
2451
2452extern int jmalloc_max_size;
2453extern int jmalloc_min_low_size;
2454
2455extern int (*verify_file_fun)(char *,char *);
2456
2457int registered_ok(char *filename, char *mode)
2458{
2459  if (registered) return 1;
2460
2461  char name[256],*c;
2462  c=name;
2463  while (*filename) { *c=*(filename++); *c=toupper(*c); c++; } *c=0;
2464  if (strstr(name,"REGISTER"))
2465    return 0;
2466  else return 1;
2467}
2468
2469void game_net_init(int argc, char **argv)
2470{
2471  int nonet=!net_init(argc, argv);
2472  if (nonet)
2473    dprintf("No network driver, or network driver returned failure\n");
2474  else
2475  {
2476    set_file_opener(open_nfs_file);
2477    if (main_net_cfg && main_net_cfg->state==net_configuration::CLIENT)
2478    {
2479      if (set_file_server(net_server))
2480      start_running=1;
2481      else
2482      {
2483                                dprintf("Unable to attach to server, quiting\n");
2484                                exit(0);
2485      }
2486    } else
2487    {
2488      int i;
2489      for (i=1;i<argc-1;i++)
2490      if (!strcmp(argv[i],"-fs"))
2491      if (!set_file_server(argv[i+1]))
2492      dprintf("could not set defualt file server to %s\n",argv[i+1]);
2493    }
2494  }     
2495
2496}
2497
2498#if (defined(__APPLE__) && !defined(__MACH__))
2499extern int PixMult;
2500#if 1
2501char cmdline[256];
2502#elif 1
2503char cmdline[] = "";
2504#elif 1
2505char cmdline[] = "abuse -server -a deathmat";
2506#else
2507char cmdline[] = "abuse -net 193.246.40.9";
2508#endif
2509char delims[] = " ";
2510char *tmp_argv[255];
2511
2512void GetArgs(int &argc, char **(&argv))
2513{
2514        char *s;
2515
2516        printf( "Usage:\n"
2517                                        "  abuse [-options]\n\n"
2518                                        "  Options:\n"
2519                                        "    -server -a deathmat        become a server for deathmatch game\n"
2520                                        "    -net <dotted ip address>   connect to a server\n\n"
2521                                        "Options for mac:\n"
2522                                        "  Hold down <control> for single pixel mode\n"
2523                                        "  Hold down <option> for edit mode\n"
2524                                        "  Hold down <left shift> for double size mode\n\n"
2525                                        "If started with no command line options, networking will attempt\n"
2526                                        "  to search the local network for servers\n\n"
2527        );
2528        printf("Enter command line:\n");
2529        gets(cmdline);
2530       
2531        argc = 0;
2532        argv = tmp_argv;
2533        s = strtok(cmdline, delims);
2534        while (s)
2535        {
2536                argv[argc] = s;
2537                argc++;
2538                s = strtok(0, delims);
2539        }
2540        argv[argc] = 0;
2541}
2542
2543#endif
2544
2545int main(int argc, char **argv)
2546{
2547#if (defined(__APPLE__) && !defined(__MACH__))
2548        GetArgs(argc,argv);
2549#endif
2550
2551        start_argc = argc;
2552        start_argv = argv;
2553
2554        for( int i = 0; i < argc; i++ )
2555        {
2556                if( !strcmp( argv[i], "-cprint" ) )
2557                {
2558                        external_print = 1;
2559                }
2560
2561                if( !strcmp( argv[i], "-min_low" ) )
2562                {
2563                        i++;
2564                        jmalloc_min_low_size = atoi( argv[i] );
2565                }
2566        }
2567
2568//  jmalloc_max_size=0x150000;
2569        jmalloc_init( 0x150000 );
2570//  jmalloc_init(100000);
2571
2572#if (defined(__APPLE__) && !defined(__MACH__))
2573        unsigned char km[16];
2574
2575        fprintf(stderr,"Mac Options: ");
2576        xres = 320; yres = 200;
2577        GetKeys((uint32_t*)&km);
2578        if ((km[ 0x3a >>3] >> (0x3a & 7)) &1 != 0)
2579        {
2580                dev|=EDIT_MODE;   
2581                start_edit=1;
2582                start_running=1;
2583                disable_autolight=1;
2584                fprintf(stderr,"Edit Mode...");
2585        }
2586        if ((km[ 0x3b >>3] >> (0x3b & 7)) &1 != 0)
2587        {
2588                PixMult = 1;
2589                fprintf(stderr,"Single Pixel...");
2590        }
2591        else
2592        {
2593                PixMult = 2;
2594                fprintf(stderr,"Double Pixel...");
2595        }
2596        if ((km[ 0x38 >>3] >> (0x38 & 7)) &1 != 0)
2597        {
2598                xres *= 2;  yres *= 2;
2599                fprintf(stderr,"Double Size...");
2600        }
2601        fprintf(stderr,"\n");
2602       
2603        if (tcpip.installed())
2604                fprintf(stderr, "Using %s\n", tcpip.name());
2605#endif
2606
2607        set_dprinter(game_printer);
2608        set_dgetter(game_getter);
2609        set_no_space_handler(handle_no_space);
2610
2611        setup(argc,argv);
2612
2613        show_startup();
2614
2615        start_sound(argc,argv);
2616
2617        stat_man = new text_status_manager();
2618        if( !get_option("-no_timer") )
2619        {
2620                timer_init();
2621        }
2622
2623        // look to see if we are supposed to fetch the data elsewhere
2624        if( getenv("ABUSE_PATH") )
2625        {
2626                set_filename_prefix( getenv( "ABUSE_PATH" ) );
2627        }
2628
2629        // look to see if we are supposed to save the data elsewhere
2630        if( getenv( "ABUSE_SAVE_PATH" ) )
2631        {
2632                set_save_filename_prefix( getenv( "ABUSE_SAVE_PATH" ) );
2633        }
2634
2635        if( !get_option( "-share" ) )
2636        {
2637                jFILE *fp = new jFILE( "register/micron.vcd", "rb" );
2638                if( !fp->open_failure() )
2639                {
2640                        spec_directory sd( fp );
2641                        if( sd.find( "Copyright (C) 1995 Crack dot Com, All Rights reserved" ) )
2642                        {
2643                                registered = 1;
2644                        }
2645                }
2646                delete fp;
2647        }
2648
2649        verify_file_fun = registered_ok;
2650
2651        jrand_init();
2652        jrand();                // so compiler doesn't complain
2653
2654        set_spec_main_file("abuse.spe");
2655
2656        check_for_lisp( argc, argv );
2657        check_for_upgrade( argc, argv );
2658
2659        do
2660        {
2661                if( main_net_cfg )
2662                {
2663                        if( !main_net_cfg->notify_reset() )
2664                        {
2665                                if( !get_option( "-no_timer" ) )
2666                                        timer_uninit();
2667                                sound_uninit();
2668                                exit(0);
2669                        }
2670                }
2671
2672                game_net_init(argc,argv);
2673                lisp_init(0x16000,0x94000);
2674//              lisp_init(0x100000,0x10000);
2675
2676                dev_init(argc,argv);
2677
2678                game *g = new game( argc, argv );
2679
2680                dev_cont=new dev_controll();
2681                dev_cont->load_stuff();
2682
2683                g->get_input();         // prime the net
2684
2685                int xx;
2686                for( xx = 1; xx < argc; xx++ )
2687                {
2688                        if (!strcmp(argv[xx],"-server"))
2689                        {
2690                                xx++;
2691                                if( !become_server( argv[xx] ) )
2692                                {
2693                                        dprintf( "unable to become a server\n" );
2694                                        exit(0);
2695                                }
2696                                xx = argc + 1;
2697                        }
2698                }
2699
2700                if( main_net_cfg )
2701                {
2702                        wait_min_players();
2703                }
2704
2705                net_send( 1 );
2706                if( net_start() )
2707                {
2708                        g->step();                              // process all the objects in the
2709                        g->calc_speed();
2710                        g->update_screen();             // redraw the screen with any changes
2711                }
2712
2713    while (!g->done())
2714    {
2715      music_check();
2716
2717      if (req_end)
2718      {
2719                                delete current_level;
2720                                current_level=NULL;
2721                               
2722                                if (!registered)
2723                                share_end();
2724                                else show_end();
2725                       
2726                                the_game->set_state(MENU_STATE);
2727                                req_end=0;
2728      }
2729
2730      if (demo_man.current_state()==demo_manager::NORMAL)
2731      {
2732                                net_receive();
2733      }
2734
2735      if (req_name[0])            // see if a request for a level load was made during the last tick
2736      {
2737        g->load_level(req_name);
2738        req_name[0]=0;
2739        g->draw(g->state==SCENE_STATE);
2740      }
2741
2742      //    if (demo_man.current_state()!=demo_manager::PLAYING)
2743      g->get_input();
2744
2745      if (demo_man.current_state()==demo_manager::NORMAL)
2746      net_send();
2747      else demo_man.do_inputs();
2748
2749      service_net_request();
2750
2751      g->step();                        // process all the objects in the
2752
2753      server_check();
2754
2755      g->calc_speed();
2756      if (!req_name[0])                // see if a request for a level load was made during the last tick
2757        g->update_screen();               // redraw the screen with any changes
2758
2759
2760    }
2761
2762    net_uninit();
2763
2764    if (net_crcs)
2765    {
2766      net_crcs->clean_up();
2767      delete net_crcs;
2768      net_crcs=NULL;
2769    }
2770
2771    delete chat;
2772
2773    if (!registered)
2774    show_sell(0);
2775    else milli_wait(500);
2776
2777
2778    if (small_render) { delete small_render; small_render=NULL; }
2779
2780    if (current_song)
2781    { current_song->stop();
2782      delete current_song;
2783      current_song=NULL;
2784    }
2785
2786
2787    cash.empty();
2788
2789
2790    if (dev_console)
2791    {
2792      delete dev_console;
2793      dev_console=NULL;
2794    }
2795
2796    if (dev_menu)
2797    {
2798      delete dev_menu;
2799      dev_menu=NULL;
2800    }
2801
2802    delete g;
2803    if (old_pal) delete old_pal; old_pal=NULL;
2804    compiled_uninit();
2805    delete_all_lights();
2806    jfree(white_light_initial);
2807
2808    for (int i=0;i<TTINTS;i++) jfree(tints[i]);
2809
2810
2811    dev_cleanup();
2812    delete dev_cont; dev_cont=NULL;
2813    delete stat_man;
2814    stat_man=new text_status_manager();
2815
2816    if (!(main_net_cfg && main_net_cfg->restart_state()))
2817    {
2818      void *end_msg=make_find_symbol("end_msg");
2819      if (DEFINEDP(symbol_value(end_msg)))
2820      printf("%s\n",lstring_value(symbol_value(end_msg)));
2821    }
2822
2823    lisp_uninit();
2824
2825    base->packet.packet_reset();
2826    mem_report("end.mem");
2827  } while (main_net_cfg && main_net_cfg->restart_state());
2828
2829        delete stat_man;
2830
2831        if( main_net_cfg )
2832        {
2833                delete main_net_cfg;
2834                main_net_cfg=NULL;
2835        }
2836        set_filename_prefix(NULL);  // dealloc this mem if there was any
2837        set_save_filename_prefix(NULL);
2838
2839        if( !get_option( "-no_timer" ) )
2840        {
2841                timer_uninit();
2842        }
2843
2844// AK -> Commented this out to stop a crash as the file prefix has already
2845//       been released.  Need to fix this.
2846//      mem_report("end.mem");
2847
2848//      jmalloc_uninit();
2849        l_user_stack.clean_up();
2850        l_ptr_stack.clean_up();
2851
2852        sound_uninit();
2853
2854        exit(0);
2855
2856        return 0;
2857}
2858
2859
Note: See TracBrowser for help on using the repository browser.