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

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