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

Last change on this file since 63 was 63, checked in by Sam Hocevar, 14 years ago
  • Minor cleanup.
File size: 62.3 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 "game.hpp"
25#include "dev.hpp"
26#include "id.hpp"
27#include "joy.hpp"
28#include "timing.hpp"
29#include "automap.hpp"
30#include "help.hpp"
31#include "ability.hpp"
32#include "cache.hpp"
33#include "loader.hpp"
34#include "lisp.hpp"
35#include "monoprnt.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                image blank( 2, 2 );
1284                blank.clear();
1285                eh->set_mouse_shape( blank.copy(), 0, 0 );      // don't show mouse
1286                fade_in( cash.img( cdc_logo ), 32 );
1287
1288                milli_wait( 900 );
1289
1290                void *space_snd = symbol_value( make_find_symbol( "SPACE_SND" ) );
1291
1292                fade_out( 32 );
1293                milli_wait( 300 );
1294
1295                int i, abort = 0;
1296                char *str = lstring_value( eval( make_find_symbol( "plot_start" ) ) );
1297
1298                bFILE *fp = open_file( "art/smoke.spe", "rb" );
1299                if( !fp->open_failure() )
1300                {
1301                        spec_directory sd( fp );
1302                        palette *old_pal = pal;
1303                        pal = new palette( sd.find( SPEC_PALETTE ), fp );
1304                        pal->shift( 1 );
1305
1306                        image *gray = new image( sd.find( "gray_pict" ), fp );
1307                        image *smoke[5];
1308
1309                        char nm[20];
1310                        for( i = 0; i < 5; i++ )
1311                        {
1312                                sprintf( nm, "smoke%04d.pcx", i + 1 );
1313                                smoke[i] = new image( sd.find( nm ), fp );
1314                        }
1315
1316                        screen->clear();
1317                        pal->load();
1318
1319                        int dx = ( xres + 1 ) / 2 - gray->width() / 2, dy = ( yres + 1 ) / 2 - gray->height() / 2;
1320                        gray->put_image( screen, dx, dy );
1321                        smoke[0]->put_image( screen, dx + 24, dy + 5 );
1322
1323                        fade_in( NULL, 16 );
1324                        uint8_t cmap[32];
1325                        for( i = 0; i < 32; i++ )
1326                        cmap[i] = pal->find_closest( i * 256 / 32, i * 256 / 32, i * 256 / 32 );
1327
1328                        event ev;
1329                        ev.type=EV_SPURIOUS;
1330                        time_marker start;
1331
1332                        for( i = 0; i < 320 && ( ev.type != EV_KEY && ev.type != EV_MOUSE_BUTTON ); i++ )
1333                        {
1334                                gray->put_image( screen, dx, dy );
1335                                smoke[i % 5]->put_image( screen, dx + 24, dy + 5 );
1336                                text_draw( 205 - i, dx + 15, dy, dx + 320 - 15, dy + 199, str, eh->font(), cmap, eh->bright_color() );
1337                                eh->flush_screen();
1338                                time_marker now;
1339
1340                                while( now.diff_time( &start ) < 0.18 )
1341                                {
1342                                        milli_wait(20); // ECS - Added the wait, so CPU utilization stays low during the story
1343                                        now.get_time();
1344                                }
1345
1346                                start.get_time();
1347
1348                                while( eh->event_waiting() && ev.type != EV_KEY)
1349                                {
1350                                        eh->get_event(ev);
1351                                }
1352                                if( ( i % 5 ) == 0 && DEFINEDP( space_snd ) && ( sound_avail & SFX_INITIALIZED ) )
1353                                {
1354                                        cash.sfx( lnumber_value( space_snd ) )->play( sfx_volume * 90 / 127 );
1355                                }
1356                        }
1357
1358                        the_game->reset_keymap();
1359
1360                        fade_out(16);
1361
1362                        for( i = 0; i < 5; i++ )
1363                                delete smoke[i];
1364                        delete gray;
1365                        delete pal;
1366                        pal = old_pal;
1367                }
1368                delete fp;
1369
1370                for( i = 0; i < 100 && !abort; i++ )
1371                {
1372                }
1373
1374                if( title_screen >= 0 )
1375                        fade_in( cash.img( title_screen ), 32 );
1376
1377                eh->set_mouse_shape( cash.img( c_normal )->copy(), 1, 1 );
1378        }
1379}
1380
1381extern int start_edit;
1382
1383void game::request_end()
1384{
1385  req_end=1;
1386}
1387
1388extern void fast_load_start_recording(char *name);
1389extern void fast_load_stop_recording();
1390extern void fast_load_start_reloading(char *name);
1391extern void fast_load_stop_reloading();
1392
1393game::game(int argc, char **argv)
1394{
1395  int i;
1396  req_name[0]=0;
1397  bg_xmul=bg_ymul=1;
1398  bg_xdiv=bg_ydiv=8;
1399  last_input=NULL;
1400  current_automap=NULL;
1401  current_level=NULL;
1402  refresh=1; 
1403  the_game=this; 
1404  top_menu=joy_win=NULL;
1405  old_view=first_view=NULL;
1406  nplayers=1;
1407
1408  help_text_frames=0; 
1409  strcpy(help_text,"");
1410
1411 
1412  for (i=1;i<argc;i++)
1413    if (!strcmp(argv[i],"-no_delay"))
1414    {
1415      no_delay=1;
1416      dprintf("Frame delay off (-nodelay)\n");
1417    }
1418
1419 
1420  image_init(); 
1421  zoom=15; 
1422  no_delay=0;
1423
1424  if (get_option("-use_joy")) 
1425  {
1426    has_joystick=joy_init(argc,argv);
1427    dprintf("Joystick : ");
1428    if (has_joystick) dprintf("detected\n");
1429    else dprintf("not detected\n");
1430  }
1431  else has_joystick=0;
1432
1433//      ProfilerInit(collectDetailed, bestTimeBase, 2000, 200); //prof
1434        char *fastpath;
1435        fastpath = (char *)jmalloc( strlen( get_save_filename_prefix() ) + 12 + 1, "fastpath" );
1436        sprintf( fastpath, "%sfastload.dat", get_save_filename_prefix() );
1437        fast_load_start_recording( fastpath );
1438        load_data(argc,argv); 
1439        fast_load_stop_recording();
1440        jfree( fastpath );
1441//      ProfilerDump("\pabuse.prof");  //prof   
1442//      ProfilerTerm();
1443
1444  get_key_bindings();
1445
1446  reset_keymap();                   // we think all the keys are up right now
1447  finished=0;
1448
1449  calc_light_table(pal);
1450
1451  if (current_level==NULL && net_start())  // if we joined a net game get level from server
1452  {
1453    if (!request_server_entry())
1454    {
1455      exit(0);
1456    }
1457    net_reload();
1458//    load_level(NET_STARTFILE);
1459  }
1460
1461
1462  set_mode(19,argc,argv);
1463  if (get_option("-2") && (xres<639 || yres<399))
1464  {
1465    close_graphics();
1466    fprintf(stderr,"Resolution must be > 640x400 to use -2 option\n");   
1467    exit(0);
1468  }
1469  pal->load();
1470 
1471  recalc_local_view_space();   // now that we know what size the screen is...
1472
1473  dark_color=get_color(cash.img(window_colors)->pixel(2,0));
1474  bright_color=get_color(cash.img(window_colors)->pixel(0,0));
1475  med_color=get_color(cash.img(window_colors)->pixel(1,0));
1476
1477  morph_dark_color=get_color(cash.img(window_colors)->pixel(2,1));
1478  morph_bright_color=get_color(cash.img(window_colors)->pixel(0,1));
1479  morph_med_color=get_color(cash.img(window_colors)->pixel(1,1));
1480  morph_sel_frame_color=pal->find_closest(255,255,0);
1481  light_connection_color=morph_sel_frame_color;
1482
1483  if (NILP(symbol_value(l_default_font)))
1484  {
1485    printf("No font defined, set symbol default-font to an image name\n");
1486    exit(0);
1487  }
1488  int font_pict;
1489  if (big_font_pict!=-1)
1490  {
1491    if (small_font_pict!=-1)
1492    {
1493      if (xres/(start_doubled ? 2 : 1)>400)
1494      {
1495        font_pict=big_font_pict;
1496      }
1497      else font_pict=small_font_pict;
1498    } else font_pict=big_font_pict;
1499  } else font_pict=small_font_pict;
1500 
1501  if (console_font_pict==-1) console_font_pict=font_pict;
1502  game_font=new JCFont(cash.img(font_pict));
1503
1504  console_font=new JCFont(cash.img(console_font_pict));
1505
1506  eh=new window_manager(screen,pal,bright_color,
1507                                   med_color,
1508                                   dark_color,
1509                                   game_font); 
1510
1511  delete stat_man;  // move to a graphical status manager
1512  gui_status_manager *gstat=new gui_status_manager(eh);
1513  gstat->set_window_title("status");
1514  stat_man=gstat;
1515
1516
1517  chat=new chat_console(eh,console_font,50,6);
1518
1519  if (!eh->has_mouse())
1520  {
1521    close_graphics();
1522    image_uninit();
1523    printf("No mouse driver detected, please rectify.\n");
1524    exit(0);
1525  }
1526
1527
1528  gamma_correct(pal);
1529
1530  if (main_net_cfg==NULL || (main_net_cfg->state!=net_configuration::SERVER &&
1531                             main_net_cfg->state!=net_configuration::CLIENT))
1532  {
1533    if (!start_edit && !net_start())
1534      do_title();
1535  } else if (main_net_cfg && main_net_cfg->state==net_configuration::SERVER)
1536  {
1537    the_game->load_level(level_file);
1538    start_running=1;
1539  }
1540   
1541
1542  dev|= DRAW_FG_LAYER | DRAW_BG_LAYER | DRAW_PEOPLE_LAYER | DRAW_HELP_LAYER | DRAW_LIGHTS | DRAW_LINKS;
1543
1544  if (dev & EDIT_MODE)
1545    set_frame_size(0);
1546//  do_intro();
1547  state=START_STATE;         // first set the state to one that has windows
1548
1549
1550  if (start_running)
1551    set_state(RUN_STATE);
1552  else
1553  {
1554    screen->clear(); 
1555    if (title_screen>=0)
1556    {
1557      image *tit=cash.img(title_screen);
1558      tit->put_image(screen,screen->width()/2-tit->width()/2,
1559                            screen->height()/2-tit->height()/2);
1560    }   
1561    set_state(MENU_STATE);   // then go to menu state so windows will turn off
1562  }
1563}
1564
1565
1566
1567time_marker *led_last_time=NULL,*fps_mark_start=NULL;
1568double avg_fps=15.0,possible_fps=15.0;
1569
1570void game::toggle_delay()
1571{
1572  no_delay=!no_delay;
1573  if (no_delay)
1574    show_help(symbol_str("delay_off"));
1575  else show_help(symbol_str("delay_on"));
1576  avg_fps=possible_fps=15.0;
1577}
1578
1579void game::show_time()
1580{
1581  if (first_view && fps_on)
1582  {
1583    char str[10];
1584    sprintf(str,"%ld",(long)(avg_fps*10.0));
1585    console_font->put_string(screen,first_view->cx1,first_view->cy1,str);
1586
1587    sprintf(str,"%d",total_active);
1588    console_font->put_string(screen,first_view->cx1,first_view->cy1+10,str);
1589  }
1590}
1591
1592void game::update_screen()
1593{
1594  if (state==HELP_STATE)
1595    draw_help();
1596  else if (current_level)
1597  {   
1598    if (!(dev & EDIT_MODE) || refresh)   
1599    {   
1600      view *f=first_view;
1601      current_level->clear_active_list();
1602      for (;f;f=f->next)
1603      {
1604        if (f->focus)           
1605        {
1606          int w,h;
1607
1608          w=(f->cx2-f->cx1+1);
1609          h=(f->cy2-f->cy1+1);
1610
1611          total_active+=current_level->add_drawables(f->xoff()-w/4,f->yoff()-h/4,
1612                                                     f->xoff()+w+w/4,f->yoff()+h+h/4);
1613
1614        }
1615      }
1616
1617      for (f=first_view;f;f=f->next)
1618      {
1619        if (f->drawable())
1620        {
1621          if (interpolate_draw)
1622          {
1623            draw_map(f,1);
1624            eh->flush_screen();
1625          }
1626          draw_map(f,0);
1627        }
1628      }
1629      if (current_automap)
1630      current_automap->draw();
1631    } 
1632    if (state==PAUSE_STATE)
1633    {
1634      for (view *f=first_view;f;f=f->next)
1635        cash.img(pause_image)->put_image(screen,(f->cx1+f->cx2)/2-cash.img(pause_image)->width()/2,
1636                               f->cy1+5,1);
1637    }
1638   
1639    show_time();
1640  }
1641
1642  if (state==RUN_STATE && cash.prof_is_on())
1643    cash.prof_poll_end();
1644
1645  eh->flush_screen();
1646
1647}
1648
1649void game::do_intro()
1650{
1651
1652}
1653
1654int game::calc_speed()
1655{
1656        int ret=0;
1657        if( fps_mark_start )
1658        {
1659                time_marker t;
1660
1661                // find average fps for last 10 frames
1662                double td=t.diff_time(fps_mark_start);
1663                if (td<0.001)     // something is rotten in the state of demark
1664                        td=0.001;
1665
1666                avg_fps=avg_fps*9.0/10.0+1.0/(td*10.0); 
1667                possible_fps=possible_fps*9.0/10.0+1.0/(td*10.0); 
1668
1669                if (avg_fps>14)
1670                {
1671                        if (massive_frame_panic>20)
1672                                massive_frame_panic=20;
1673                        else if (massive_frame_panic)
1674                                massive_frame_panic--;
1675                }
1676
1677                if (avg_fps>15 && ((dev&EDIT_MODE)==0 || need_delay))
1678                {
1679                        frame_panic = 0;
1680                        int32_t stime=(int32_t)((1/15.0-1.0/possible_fps)*1000.0);
1681                        if (stime>0 && !no_delay)
1682                        {
1683                                milli_wait(stime);
1684                                avg_fps-=1.0/(td*10.0);   // subtract out old estimate
1685
1686                                time_marker t;
1687
1688                                // find average fps for last 10 frames
1689                                double td=t.diff_time(fps_mark_start);
1690                                if (td<0.00001)     // something is rotten in the state of demark
1691                                        td=0.00001;
1692
1693                                avg_fps+=1.0/(td*10.0);       // add in new estimate
1694                        }
1695                }
1696                else if (avg_fps<14)
1697                {
1698                        if (avg_fps<10)
1699                                massive_frame_panic++;
1700                        frame_panic++;
1701                        ret=1;
1702                }
1703                else if( dev & EDIT_MODE )
1704                {
1705                        // ECS - Added this case and the wait.  It's a cheap hack to assure that
1706                        // we don't exceed 30FPS in edit mode and hog the CPU.
1707                        milli_wait(33);
1708                }
1709
1710                delete fps_mark_start;   
1711        }
1712        fps_mark_start=new time_marker;
1713        return ret;
1714}
1715
1716extern int start_edit;
1717
1718void game::get_input()
1719{
1720        event ev;
1721        idle_ticks++;
1722        while( event_waiting( eh ) )
1723        {
1724                get_event(ev,eh);
1725
1726                if(ev.type == EV_MOUSE_MOVE )
1727                {
1728                        last_input = ev.window;
1729                }
1730                // don't process repeated keys in the main window, it will slow down the game to handle such
1731                // useless events. However in other windows it might be useful, such as in input windows
1732                // where you want to repeatedly scroll down...
1733                if( ev.type != EV_KEY || !key_down( ev.key ) || ev.window || ( dev & EDIT_MODE ) )
1734                {
1735                        if( ev.type == EV_KEY )
1736                        {
1737                                set_key_down( ev.key, 1 );
1738                                if( playing_state( state ) )
1739                                {
1740                                        if(ev.key < 256 )
1741                                        {
1742                                                if( chat && chat->chat_event( ev ) )
1743                                                        base->packet.write_uint8( SCMD_CHAT_KEYPRESS );
1744                                                else
1745                                                        base->packet.write_uint8( SCMD_KEYPRESS );
1746                                        }
1747                                        else
1748                                                base->packet.write_uint8( SCMD_EXT_KEYPRESS );
1749                                        base->packet.write_uint8( client_number() );
1750                                        if( ev.key > 256 )
1751                                                base->packet.write_uint8( ev.key - 256 );
1752                                        else
1753                                                base->packet.write_uint8( ev.key );
1754                                }
1755                        }
1756                        else if(ev.type == EV_KEYRELEASE )
1757                        {
1758                                set_key_down( ev.key, 0 );
1759                                if( playing_state( state ) )
1760                                {
1761                                        if( ev.key < 256 )
1762                                                base->packet.write_uint8( SCMD_KEYRELEASE );
1763                                        else
1764                                                base->packet.write_uint8( SCMD_EXT_KEYRELEASE );
1765                                        base->packet.write_uint8( client_number() );
1766                                        if( ev.key > 255 )
1767                                                base->packet.write_uint8( ev.key - 256 );
1768                                        else
1769                                                base->packet.write_uint8( ev.key );
1770                                }
1771                        }
1772
1773                        if( (dev & EDIT_MODE) || start_edit || ev.type == EV_MESSAGE )
1774                        {
1775                                dev_cont->handle_event( ev );
1776                        }
1777
1778                        view *v = first_view;
1779                        for( ; v; v = v->next )
1780                        {
1781                                if( v->local_player() && v->handle_event( ev ) )
1782                                        ev.type=EV_SPURIOUS;       // if the event was used by the view, gobble it up
1783                        }
1784
1785                        if( current_automap )
1786                        {
1787                                current_automap->handle_event( ev );
1788                        }
1789
1790                        help_handle_event( ev );
1791                        mousex = last_demo_mx;
1792                        mousey = last_demo_my;
1793
1794                        if(ev.type == EV_MESSAGE )
1795                        {
1796                                switch (ev.message.id)
1797                                {
1798                                        case CALB_JOY:
1799                                        {
1800                                                if (!joy_win)
1801                                                {
1802                                                        int wx=WINDOW_FRAME_LEFT,wy=WINDOW_FRAME_TOP;
1803
1804                                                        joy_win=eh->new_window(80,50,-1,-1,
1805                                                                        new button(wx+70,wy+9,JOY_OK,"OK",
1806                                                                        new info_field(wx,wy+30,DEV_NULL,
1807                                                                        " Center joystick and\n"
1808                                                                        "press the fire button",NULL)),
1809                                                                        "Joystick");
1810                                                        set_state(JOY_CALB_STATE);
1811                                                }
1812                                        }
1813                                        case TOP_MENU:
1814                                        {
1815                                                menu_select(ev);
1816                                        } break;
1817                                        case DEV_QUIT:
1818                                        {
1819                                                finished = 1;
1820                                        } break;
1821                                }
1822                        }
1823                        else if(ev.type == EV_CLOSE_WINDOW && ev.window == top_menu )
1824                        {
1825                                eh->close_window( top_menu );
1826                                top_menu = NULL;
1827                        }
1828
1829                        switch( state )
1830                        {
1831                                case JOY_CALB_STATE:
1832                                {
1833                                        joy_calb(ev);
1834                                } break;
1835                                case INTRO_START_STATE:
1836                                {
1837                                        do_intro();
1838                                        if (dev & EDIT_MODE)
1839                                                set_state(RUN_STATE);
1840                                        else
1841                                                set_state(MENU_STATE);
1842                                } break;
1843                                case PAUSE_STATE:
1844                                {
1845                                        if( ev.type == EV_KEY && ( ev.key == JK_SPACE || ev.key == JK_ENTER ) )
1846                                        {
1847                                                set_state( RUN_STATE );
1848                                        }
1849                                } break;
1850                                case RUN_STATE:
1851                                {
1852                                        if (ev.window==NULL)
1853                                        {
1854                                                switch (ev.type)
1855                                                {
1856                                                        case EV_KEY:
1857                                                        {
1858                                                                switch (ev.key)
1859                                                                {
1860                                                                        case 'm':
1861                                                                        {
1862                                                                                if( dev & MAP_MODE )
1863                                                                                        dev -= MAP_MODE;
1864                                                                                else if( ( player_list && player_list->next ) || dev & EDIT_MODE )
1865                                                                                        dev |= MAP_MODE;
1866
1867                                                                                if( !( dev & MAP_MODE ) )
1868                                                                                {
1869                                                                                        if( dev_cont->tbw )
1870                                                                                                dev_cont->toggle_toolbar();
1871                                                                                        edit_mode = ID_DMODE_DRAW;
1872                                                                                }
1873                                                                                need_refresh();
1874                                                                        } break;
1875                                                                        case 'v':
1876                                                                        {
1877                                                                                eh->push_event(new event(DO_VOLUME,NULL));
1878                                                                        } break;
1879                                                                        case 'p':
1880                                                                        {
1881                                                                                if (!(dev&EDIT_MODE) && (!main_net_cfg ||
1882                                                                                        (main_net_cfg->state!=net_configuration::SERVER &&
1883                                                                                        main_net_cfg->state!=net_configuration::CLIENT)))
1884                                                                                {
1885                                                                                        set_state(PAUSE_STATE);
1886                                                                                }
1887                                                                        } break;
1888                                                                        case 'S':
1889                                                                        {
1890                                                                                if( start_edit )
1891                                                                                {
1892                                                                                        eh->push_event(new event(ID_LEVEL_SAVE,NULL));
1893                                                                                }
1894                                                                        } break;
1895                                                                        case JK_TAB:
1896                                                                        {
1897                                                                                if( start_edit )
1898                                                                                        toggle_edit_mode();
1899                                                                                need_refresh();
1900                                                                        } break;
1901                                                                        case 'c':
1902                                                                        {
1903                                                                                if( chatting_enabled && (!(dev&EDIT_MODE) && chat))
1904                                                                                        chat->toggle();
1905                                                                        } break;
1906                                                                        case '9':
1907                                                                        {
1908                                                                                dev = dev^PERFORMANCE_TEST_MODE;
1909                                                                                need_refresh();
1910                                                                        } break;
1911/*                                                                      case '=':
1912                                                                        case '+':
1913                                                                        {
1914                                                                                if (!dev_cont->need_plus_minus())
1915                                                                                {
1916                                                                                        if (eh->key_pressed(JK_CTRL_L))
1917                                                                                                grow_views(20);
1918                                                                                        else
1919                                                                                                grow_views(5);
1920                                                                                        draw(state==SCENE_STATE);
1921                                                                                }
1922                                                                        } break;
1923                                                                        case JK_F10:
1924                                                                        {
1925                                                                                make_screen_size(311,160);
1926                                                                        } break;
1927                                                                        case '_':
1928                                                                        case '-' :
1929                                                                        {
1930                                                                                if (!dev_cont->need_plus_minus())
1931                                                                                {
1932                                                                                        if (eh->key_pressed(JK_CTRL_L))
1933                                                                                                grow_views(-20);
1934                                                                                        else
1935                                                                                                grow_views(-5);
1936                                                                                        draw(state==SCENE_STATE);
1937                                                                                }
1938                                                                        } break;
1939*/
1940                                                                }
1941                                                        } break;
1942                                                        case EV_RESIZE:
1943                                                        {
1944                                                                view *v;
1945                                                                for( v = first_view; v; v = v->next )  // see if any views need to change size
1946                                                                {
1947                                                                        if (v->local_player())
1948                                                                        {
1949                                                                                int w = (xres-10)/(small_render ? 2 : 1);
1950                                                                                int h = (yres-10)/(small_render ? 2 : 1);
1951
1952                                                                                v->suggest.send_view = 1;
1953                                                                                v->suggest.cx1 = 5;
1954                                                                                v->suggest.cx2 = 5 + w;
1955                                                                                v->suggest.cy1 = 5;
1956                                                                                v->suggest.cy2 = 5 + h;
1957                                                                                v->suggest.pan_x = v->pan_x;
1958                                                                                v->suggest.pan_y = v->pan_y;
1959                                                                                v->suggest.shift_down = v->shift_down;
1960                                                                                v->suggest.shift_right = v->shift_right;
1961                                                                        }
1962                                                                }
1963                                                                draw();
1964                                                        } break;
1965                                                        case EV_REDRAW:
1966                                                        {
1967                                                                screen->add_dirty(ev.redraw.x1,ev.redraw.y1,
1968                                                                        ev.redraw.x2,ev.redraw.y2);
1969                                                        } break;
1970                                                        case EV_MESSAGE:
1971                                                        {
1972                                                                switch (ev.message.id)
1973                                                                {
1974                                                                        case RAISE_SFX:
1975                                                                        case LOWER_SFX:
1976                                                                        case RAISE_MUSIC:
1977                                                                        case LOWER_MUSIC:
1978                                                                        {
1979                                                                                if( ev.message.id == RAISE_SFX && sfx_volume != 127 )
1980                                                                                        sfx_volume = min( 127, sfx_volume + 16 );
1981                                                                                if( ev.message.id == LOWER_SFX && sfx_volume != 0 )
1982                                                                                        sfx_volume = max( sfx_volume - 16,0 );
1983                                                                                if( ev.message.id == RAISE_MUSIC && music_volume != 126 )
1984                                                                                {
1985                                                                                        music_volume = min( music_volume + 16, 127 );
1986                                                                                        if( current_song && ( sound_avail & MUSIC_INITIALIZED ) )
1987                                                                                                current_song->set_volume( music_volume );
1988                                                                                }
1989
1990                                                                                if( ev.message.id == LOWER_MUSIC && music_volume != 0 )
1991                                                                                {
1992                                                                                        music_volume = max( music_volume - 16, 0 );
1993                                                                                        if( current_song && (sound_avail & MUSIC_INITIALIZED ) )
1994                                                                                                current_song->set_volume( music_volume );
1995                                                                                }
1996
1997                                                                                ((button *)ev.message.data)->push();
1998/*                                                                              volume_window->inm->redraw();
1999                                                                                draw_value(volume_window->screen,WINDOW_FRAME_LEFT+2,WINDOW_FRAME_TOP+43,
2000                                                                                                (volume_window->x2()-volume_window->x1()-1),8, sfx_volume,127);
2001                                                                                draw_value(volume_window->screen,WINDOW_FRAME_LEFT+2,WINDOW_FRAME_TOP+94,
2002                                                                                                (volume_window->x2()-volume_window->x1()-1),8, music_volume,127);
2003*/
2004                                                                                break;
2005                                                                        }
2006                                                                }
2007                                                        }
2008                                                }
2009                                        }
2010                                } break;
2011                        }
2012                }
2013        }
2014}
2015
2016
2017void net_send(int force=0)
2018{
2019  if ( (!(dev&EDIT_MODE)) || force)
2020  {
2021    if (demo_man.state==demo_manager::PLAYING)
2022    {
2023      base->input_state=INPUT_PROCESSING;
2024    } else
2025    {
2026     
2027
2028
2029      if (!player_list->focus)
2030      {
2031        dprintf("Players have not been created\ncall create_players");
2032        exit(0);
2033      }
2034
2035
2036      view *p=player_list;
2037      for (;p;p=p->next)
2038        if (p->local_player())
2039          p->get_input();
2040
2041
2042      base->packet.write_uint8(SCMD_SYNC);
2043      base->packet.write_uint16(make_sync());
2044
2045      if (base->join_list)
2046      base->packet.write_uint8(SCMD_RELOAD);
2047
2048      //      printf("save tick %d, pk size=%d, rand_on=%d, sync=%d\n",current_level->tick_counter(),
2049      //             base->packet.packet_size(),rand_on,make_sync());
2050      send_local_request();
2051    }
2052  }
2053}
2054
2055void net_receive()
2056{
2057  if (!(dev&EDIT_MODE) && current_level)
2058  {
2059    uint8_t buf[PACKET_MAX_SIZE+1];
2060    int size;
2061
2062    if (demo_man.state==demo_manager::PLAYING)
2063    {
2064      if (!demo_man.get_packet(buf,size))
2065        size=0;
2066      base->packet.packet_reset();
2067      base->mem_lock=0;
2068    } else
2069    {
2070      size=get_inputs_from_server(buf);
2071      if (demo_man.state==demo_manager::RECORDING)
2072        demo_man.save_packet(buf,size);
2073    }
2074
2075    process_packet_commands(buf,size);
2076  }
2077}
2078
2079void game::step()
2080{
2081  clear_tmp();
2082  if (current_level)
2083  {
2084    current_level->unactivate_all();
2085    total_active=0;
2086    for (view *f=first_view;f;f=f->next)
2087    {
2088      if (f->focus)           
2089      {
2090        f->update_scroll();
2091        int w,h;
2092
2093        w=(f->cx2-f->cx1+1);
2094        h=(f->cy2-f->cy1+1);
2095        total_active+=current_level->add_actives(f->xoff()-w/4,f->yoff()-h/4,
2096                                                 f->xoff()+w+w/4,f->yoff()+h+h/4);
2097      }
2098    }
2099  }
2100
2101  if (state==RUN_STATE)
2102  {   
2103    if ((dev&EDIT_MODE) || (main_net_cfg && (main_net_cfg->state==net_configuration::CLIENT ||
2104                                             main_net_cfg->state==net_configuration::SERVER)))
2105      idle_ticks=0;
2106
2107    if (demo_man.current_state()==demo_manager::NORMAL && idle_ticks>420 && demo_start)
2108    {
2109      idle_ticks=0;
2110      set_state(MENU_STATE);   
2111    }
2112    else if (!(dev & EDIT_MODE))               // if edit mode, then don't step anything
2113    {
2114      if (key_down(JK_ESC))
2115      {
2116        set_state(MENU_STATE);
2117        set_key_down(JK_ESC,0);
2118      }
2119      ambient_ramp=0;
2120      view *v;
2121      for (v=first_view;v;v=v->next)
2122        v->update_scroll();
2123
2124      cash.prof_poll_start();
2125      current_level->tick();
2126      sbar.step();
2127    } else   
2128      dev_scroll(); 
2129  } else if (state==JOY_CALB_STATE)
2130  {
2131    event ev;
2132    joy_calb(ev);
2133  } else if (state==MENU_STATE) 
2134    main_menu(); 
2135   
2136  if (key_down('x') && (key_down(JK_ALT_L) || key_down(JK_ALT_R)) && confirm_quit()) finished=1;
2137}
2138
2139extern void *current_demo;
2140
2141game::~game()
2142{
2143  current_demo=NULL;
2144  if (first_view==player_list) first_view=NULL;
2145  while (player_list)
2146  {
2147    view *p=player_list;
2148    game_object *o=p->focus;
2149    player_list=player_list->next;
2150    delete p;
2151    o->set_controller(NULL);
2152    if (current_level && o)
2153      current_level->delete_object(o);
2154    else delete o;
2155  }
2156
2157  if (current_level) { delete current_level; current_level=NULL; }
2158
2159  if (first_view!=player_list)
2160  {
2161    while (player_list)
2162    {
2163      view *p=player_list;
2164      player_list=player_list->next;
2165      delete p;
2166    }
2167  }
2168
2169  while (first_view)
2170  {
2171    view *p=first_view;
2172    first_view=first_view->next;
2173    delete p;
2174  }
2175
2176  player_list=NULL; 
2177
2178  if (old_view)
2179  {
2180    first_view=old_view;
2181    while (first_view)
2182    {
2183      view *p=first_view;
2184      first_view=first_view->next;
2185      delete p;
2186    }
2187  }
2188  old_view=NULL;
2189
2190  int i=0;
2191  for (;i<total_objects;i++)
2192  {
2193    jfree(object_names[i]);
2194    delete figures[i];
2195  }
2196  free_pframes();
2197  if (fps_mark_start) delete fps_mark_start; fps_mark_start=NULL;
2198  delete pal;
2199  jfree(object_names);
2200  jfree(figures);
2201
2202  jfree(backtiles);
2203  jfree(foretiles);
2204  if (total_weapons)
2205    jfree(weapon_types);
2206
2207  config_cleanup();
2208  delete color_table;
2209  delete eh;
2210  delete game_font;
2211  delete big_font;
2212  delete console_font;
2213  if (total_help_screens)
2214    jfree(help_screens);
2215   
2216  close_graphics();
2217  image_uninit();
2218}
2219
2220
2221
2222void game::draw(int scene_mode)
2223{
2224        screen->add_dirty( 0, 0, xres, yres );
2225//      image *bt=cash.img(border_tile);
2226//      int tw=bt->width(),th=bt->height();
2227  screen->clear();
2228//  for (y=0;y<yt;y++,dy+=th)
2229//    for (x=0,dx=0;x<xt;x++,dx+=tw)
2230//      bt->put_image(screen,dx,dy);
2231
2232        if( scene_mode )
2233        {
2234                char const *helpstr = "ARROW KEYS CHANGE TEXT SPEED";
2235                eh->font()->put_string(screen,screen->width()/2-(eh->font()->width()*strlen(helpstr))/2+1,
2236                        screen->height()-eh->font()->height()-5+1,helpstr,eh->dark_color());
2237                eh->font()->put_string(screen,screen->width()/2-(eh->font()->width()*strlen(helpstr))/2,
2238                        screen->height()-eh->font()->height()-5,helpstr,eh->bright_color());   
2239        }
2240/*      else
2241        {
2242                char *helpstr="PRESS h FOR HELP";
2243                eh->font()->put_string(screen,screen->width()-eh->font()->width()*strlen(helpstr)-5,
2244                        screen->height()-eh->font()->height()-5,helpstr);
2245        }*/
2246/*      int dc=cash.img(window_colors)->pixel(0,2);
2247        int mc=cash.img(window_colors)->pixel(1,2);
2248        int bc=cash.img(window_colors)->pixel(2,2);
2249        screen->line(0,0,screen->width()-1,0,dc);
2250        screen->line(0,0,0,screen->height()-1,dc);
2251        screen->line(0,screen->height()-1,screen->width()-1,screen->height()-1,bc);
2252        screen->line(screen->width()-1,0,screen->width()-1,screen->height()-1,bc); */
2253
2254        for( view *f = first_view; f; f = f->next )
2255                draw_map( f, 0 );
2256
2257        sbar.redraw( screen );
2258}
2259
2260int external_print=0;
2261
2262void start_sound(int argc, char **argv)
2263{
2264  sfx_volume=music_volume=127;
2265
2266  for (int i=1;i<argc;i++)
2267    if (!strcmp(argv[i],"-sfx_volume"))
2268    {
2269      i++;
2270      if (atoi(argv[i])>=0 && atoi(argv[i])<127)
2271        sfx_volume=atoi(argv[i]);
2272      else printf("Bad sound effects volume level, use 0..127\n");     
2273    }
2274    else if (!strcmp(argv[i],"-music_volume"))
2275    {
2276      i++;
2277      if (atoi(argv[i])>=0 && atoi(argv[i])<127)
2278        music_volume=atoi(argv[i]);
2279      else printf("Bad music volume level, use 0..127\n");     
2280    }
2281
2282  sound_avail=sound_init(argc,argv);
2283}
2284
2285void game_printer(char *st)
2286{
2287  if (dev_console && !external_print)
2288  {
2289    dev_console->put_string(st);
2290  }
2291  else fprintf(stderr,"%s",st);
2292}
2293
2294
2295void game_getter(char *st, int max)
2296{
2297  if (!max) return ;
2298  max--;
2299  *st=0;
2300  if (dev_console && !external_print)
2301  {   
2302    dev_console->show();
2303    int t=0;
2304    event ev;
2305    do
2306    {
2307      get_event(ev,eh);
2308      if (ev.type==EV_KEY)
2309      {
2310        if (ev.key==JK_BACKSPACE)
2311        {
2312          if (t)
2313          {
2314            dev_console->print_f("%c",ev.key);
2315            t--;
2316            st--;
2317            *st=0;
2318            max++;
2319          }
2320        } else if (ev.key>=' ' && ev.key<='~')
2321        {
2322          dev_console->print_f("%c",ev.key);
2323          *st=ev.key;
2324          t++;
2325          max--;
2326          st++;
2327          *st=0;
2328        }                         
2329      }
2330      eh->flush_screen();
2331    } while (ev.type!=EV_KEY || ev.key!=JK_ENTER);   
2332    dprintf("\n");
2333  }
2334  else
2335  {
2336    if (fgets(st,max,stdin))
2337    {
2338      if (*st)
2339        st[strlen(st)-1]=0;
2340    }
2341  }
2342}
2343
2344
2345void show_startup()
2346{
2347  show_verinfo(start_argc,start_argv);
2348}
2349
2350char *get_line(int open_braces)
2351{
2352  char *line=(char *)jmalloc(1000,"lstring");
2353  fgets(line,1000,stdin);
2354
2355  char prev=' ';
2356  for (char *s=line;*s && (prev!=' ' || *s!=';');s++)
2357  {
2358    prev=*s;
2359    if (*s=='(') open_braces++;
2360    else if (*s==')') open_braces--;
2361  }
2362  if (open_braces<0)   
2363    fprintf(stderr,"\nToo many )'s\n");
2364  else if (open_braces>0)
2365  {
2366    char *s2=get_line(open_braces);
2367    line=(char *)jrealloc(line,strlen(line)+strlen(s2)+1,"lstring");
2368    strcat(line,s2);
2369    jfree(s2);   
2370  } 
2371  return line;
2372}
2373
2374void check_for_upgrade(int argc, char **argv)
2375{
2376  for (int i=1;i<argc;i++)
2377    if (!strcmp(argv[i],"-upgrade"))
2378    {
2379      lisp_init(0xf000,0x30000);
2380      char const *prog="(load \"lisp/upgrade.lsp\")";
2381      char const *cs = prog;
2382      if (!eval(compile(cs)))
2383        printf("file does not exists : lisp/upgrade.lsp, cannot upgrade\n");
2384
2385      exit(0);
2386    }       
2387}
2388
2389void check_for_lisp(int argc, char **argv)
2390{
2391        for( int i = 1; i < argc; i++ )
2392        {
2393                if( !strcmp( argv[i], "-lisp" ) )
2394                {
2395                        lisp_init(0xf000,0x30000);
2396                        char const *eof_char = "CTRL-D";
2397                        fprintf(stderr,
2398                                        " CLIVE (C) 1995 Jonathan Clark, all rights reserved\n"
2399                                        "   (C LISP interpreter and various extentions)\n"
2400                                        "Type (%s) to exit\n",eof_char);
2401
2402                        while (!feof(stdin))
2403                        {
2404                                fprintf(stderr,"Lisp> ");
2405                                char *l = get_line(0);
2406                                char const *s = l;
2407                                while (*s)
2408                                {
2409                                        void *prog=compile(s);
2410                                        l_user_stack.push(prog);
2411                                        while (*s==' ' || *s=='\t' || *s=='\r' || *s=='\n') s++;
2412                                        lprint(eval(prog));
2413                                        l_user_stack.pop(1);
2414                                }
2415                                jfree(l);
2416                        }
2417                        fprintf(stderr,"End of input : bye\n");
2418                        exit(0);
2419                }
2420        }
2421}
2422
2423
2424void music_check()
2425{
2426  if (sound_avail&MUSIC_INITIALIZED)
2427  {
2428    if (current_song && !current_song->playing())
2429    {
2430      current_song->play();
2431      dprintf("song finished\n");
2432    }
2433    if (!current_song)
2434    {
2435
2436      current_song=new song("music/intro.hmi");
2437      current_song->play(music_volume);
2438
2439/*      if (DEFINEDP(symbol_function(l_next_song)))  // if user function installed, call it to load up next song
2440      {
2441        int sp=current_space;
2442        current_space=PERM_SPACE;
2443        eval_function((lisp_symbol *)l_next_song,NULL);
2444        current_space=sp;
2445      } */
2446    }
2447  }
2448}
2449
2450void setup(int argc, char **argv);
2451
2452void share_end();
2453void show_end();
2454
2455void show_sell(int abortable);
2456
2457extern pmenu *dev_menu;
2458
2459
2460extern int jmalloc_max_size;
2461extern int jmalloc_min_low_size;
2462
2463void game_net_init(int argc, char **argv)
2464{
2465  int nonet=!net_init(argc, argv);
2466  if (nonet)
2467    dprintf("No network driver, or network driver returned failure\n");
2468  else
2469  {
2470    set_file_opener(open_nfs_file);
2471    if (main_net_cfg && main_net_cfg->state==net_configuration::CLIENT)
2472    {
2473      if (set_file_server(net_server))
2474      start_running=1;
2475      else
2476      {
2477                                dprintf("Unable to attach to server, quiting\n");
2478                                exit(0);
2479      }
2480    } else
2481    {
2482      int i;
2483      for (i=1;i<argc-1;i++)
2484      if (!strcmp(argv[i],"-fs"))
2485      if (!set_file_server(argv[i+1]))
2486      dprintf("could not set defualt file server to %s\n",argv[i+1]);
2487    }
2488  }     
2489
2490}
2491
2492#if (defined(__APPLE__) && !defined(__MACH__))
2493extern int PixMult;
2494#if 1
2495char cmdline[256];
2496#elif 1
2497char cmdline[] = "";
2498#elif 1
2499char cmdline[] = "abuse -server -a deathmat";
2500#else
2501char cmdline[] = "abuse -net 193.246.40.9";
2502#endif
2503char delims[] = " ";
2504char *tmp_argv[255];
2505
2506void GetArgs(int &argc, char **(&argv))
2507{
2508        char *s;
2509
2510        printf( "Usage:\n"
2511                                        "  abuse [-options]\n\n"
2512                                        "  Options:\n"
2513                                        "    -server -a deathmat        become a server for deathmatch game\n"
2514                                        "    -net <dotted ip address>   connect to a server\n\n"
2515                                        "Options for mac:\n"
2516                                        "  Hold down <control> for single pixel mode\n"
2517                                        "  Hold down <option> for edit mode\n"
2518                                        "  Hold down <left shift> for double size mode\n\n"
2519                                        "If started with no command line options, networking will attempt\n"
2520                                        "  to search the local network for servers\n\n"
2521        );
2522        printf("Enter command line:\n");
2523        gets(cmdline);
2524       
2525        argc = 0;
2526        argv = tmp_argv;
2527        s = strtok(cmdline, delims);
2528        while (s)
2529        {
2530                argv[argc] = s;
2531                argc++;
2532                s = strtok(0, delims);
2533        }
2534        argv[argc] = 0;
2535}
2536
2537#endif
2538
2539int main(int argc, char **argv)
2540{
2541#if (defined(__APPLE__) && !defined(__MACH__))
2542        GetArgs(argc,argv);
2543#endif
2544
2545        start_argc = argc;
2546        start_argv = argv;
2547
2548        for( int i = 0; i < argc; i++ )
2549        {
2550                if( !strcmp( argv[i], "-cprint" ) )
2551                {
2552                        external_print = 1;
2553                }
2554
2555                if( !strcmp( argv[i], "-min_low" ) )
2556                {
2557                        i++;
2558                        jmalloc_min_low_size = atoi( argv[i] );
2559                }
2560        }
2561
2562//  jmalloc_max_size=0x150000;
2563        jmalloc_init( 0x150000 );
2564//  jmalloc_init(100000);
2565
2566#if (defined(__APPLE__) && !defined(__MACH__))
2567        unsigned char km[16];
2568
2569        fprintf(stderr,"Mac Options: ");
2570        xres = 320; yres = 200;
2571        GetKeys((uint32_t*)&km);
2572        if ((km[ 0x3a >>3] >> (0x3a & 7)) &1 != 0)
2573        {
2574                dev|=EDIT_MODE;   
2575                start_edit=1;
2576                start_running=1;
2577                disable_autolight=1;
2578                fprintf(stderr,"Edit Mode...");
2579        }
2580        if ((km[ 0x3b >>3] >> (0x3b & 7)) &1 != 0)
2581        {
2582                PixMult = 1;
2583                fprintf(stderr,"Single Pixel...");
2584        }
2585        else
2586        {
2587                PixMult = 2;
2588                fprintf(stderr,"Double Pixel...");
2589        }
2590        if ((km[ 0x38 >>3] >> (0x38 & 7)) &1 != 0)
2591        {
2592                xres *= 2;  yres *= 2;
2593                fprintf(stderr,"Double Size...");
2594        }
2595        fprintf(stderr,"\n");
2596       
2597        if (tcpip.installed())
2598                fprintf(stderr, "Using %s\n", tcpip.name());
2599#endif
2600
2601        set_dprinter(game_printer);
2602        set_dgetter(game_getter);
2603        set_no_space_handler(handle_no_space);
2604
2605        setup(argc,argv);
2606
2607        show_startup();
2608
2609        start_sound(argc,argv);
2610
2611        stat_man = new text_status_manager();
2612        if( !get_option("-no_timer") )
2613        {
2614                timer_init();
2615        }
2616
2617        // look to see if we are supposed to fetch the data elsewhere
2618        if( getenv("ABUSE_PATH") )
2619        {
2620                set_filename_prefix( getenv( "ABUSE_PATH" ) );
2621        }
2622
2623        // look to see if we are supposed to save the data elsewhere
2624        if( getenv( "ABUSE_SAVE_PATH" ) )
2625        {
2626                set_save_filename_prefix( getenv( "ABUSE_SAVE_PATH" ) );
2627        }
2628
2629        jrand_init();
2630        jrand();                // so compiler doesn't complain
2631
2632        set_spec_main_file("abuse.spe");
2633
2634        check_for_lisp( argc, argv );
2635        check_for_upgrade( argc, argv );
2636
2637        do
2638        {
2639                if( main_net_cfg )
2640                {
2641                        if( !main_net_cfg->notify_reset() )
2642                        {
2643                                if( !get_option( "-no_timer" ) )
2644                                        timer_uninit();
2645                                sound_uninit();
2646                                exit(0);
2647                        }
2648                }
2649
2650                game_net_init(argc,argv);
2651                lisp_init(0x16000,0x94000);
2652//              lisp_init(0x100000,0x10000);
2653
2654                dev_init(argc,argv);
2655
2656                game *g = new game( argc, argv );
2657
2658                dev_cont=new dev_controll();
2659                dev_cont->load_stuff();
2660
2661                g->get_input();         // prime the net
2662
2663                int xx;
2664                for( xx = 1; xx < argc; xx++ )
2665                {
2666                        if (!strcmp(argv[xx],"-server"))
2667                        {
2668                                xx++;
2669                                if( !become_server( argv[xx] ) )
2670                                {
2671                                        dprintf( "unable to become a server\n" );
2672                                        exit(0);
2673                                }
2674                                xx = argc + 1;
2675                        }
2676                }
2677
2678                if( main_net_cfg )
2679                {
2680                        wait_min_players();
2681                }
2682
2683                net_send( 1 );
2684                if( net_start() )
2685                {
2686                        g->step();                              // process all the objects in the
2687                        g->calc_speed();
2688                        g->update_screen();             // redraw the screen with any changes
2689                }
2690
2691    while (!g->done())
2692    {
2693      music_check();
2694
2695      if (req_end)
2696      {
2697                                delete current_level;
2698                                current_level=NULL;
2699                               
2700                                show_end();
2701                       
2702                                the_game->set_state(MENU_STATE);
2703                                req_end=0;
2704      }
2705
2706      if (demo_man.current_state()==demo_manager::NORMAL)
2707      {
2708                                net_receive();
2709      }
2710
2711      if (req_name[0])            // see if a request for a level load was made during the last tick
2712      {
2713        g->load_level(req_name);
2714        req_name[0]=0;
2715        g->draw(g->state==SCENE_STATE);
2716      }
2717
2718      //    if (demo_man.current_state()!=demo_manager::PLAYING)
2719      g->get_input();
2720
2721      if (demo_man.current_state()==demo_manager::NORMAL)
2722      net_send();
2723      else demo_man.do_inputs();
2724
2725      service_net_request();
2726
2727      g->step();                        // process all the objects in the
2728
2729      server_check();
2730
2731      g->calc_speed();
2732      if (!req_name[0])                // see if a request for a level load was made during the last tick
2733        g->update_screen();               // redraw the screen with any changes
2734
2735
2736    }
2737
2738    net_uninit();
2739
2740    if (net_crcs)
2741    {
2742      net_crcs->clean_up();
2743      delete net_crcs;
2744      net_crcs=NULL;
2745    }
2746
2747    delete chat;
2748
2749    milli_wait(500);
2750
2751    if (small_render) { delete small_render; small_render=NULL; }
2752
2753    if (current_song)
2754    { current_song->stop();
2755      delete current_song;
2756      current_song=NULL;
2757    }
2758
2759
2760    cash.empty();
2761
2762
2763    if (dev_console)
2764    {
2765      delete dev_console;
2766      dev_console=NULL;
2767    }
2768
2769    if (dev_menu)
2770    {
2771      delete dev_menu;
2772      dev_menu=NULL;
2773    }
2774
2775    delete g;
2776    if (old_pal) delete old_pal; old_pal=NULL;
2777    compiled_uninit();
2778    delete_all_lights();
2779    jfree(white_light_initial);
2780
2781    for (int i=0;i<TTINTS;i++) jfree(tints[i]);
2782
2783
2784    dev_cleanup();
2785    delete dev_cont; dev_cont=NULL;
2786    delete stat_man;
2787    stat_man=new text_status_manager();
2788
2789    if (!(main_net_cfg && main_net_cfg->restart_state()))
2790    {
2791      void *end_msg=make_find_symbol("end_msg");
2792      if (DEFINEDP(symbol_value(end_msg)))
2793      printf("%s\n",lstring_value(symbol_value(end_msg)));
2794    }
2795
2796    lisp_uninit();
2797
2798    base->packet.packet_reset();
2799    mem_report("end.mem");
2800  } while (main_net_cfg && main_net_cfg->restart_state());
2801
2802        delete stat_man;
2803
2804        if( main_net_cfg )
2805        {
2806                delete main_net_cfg;
2807                main_net_cfg=NULL;
2808        }
2809        set_filename_prefix(NULL);  // dealloc this mem if there was any
2810        set_save_filename_prefix(NULL);
2811
2812        if( !get_option( "-no_timer" ) )
2813        {
2814                timer_uninit();
2815        }
2816
2817// AK -> Commented this out to stop a crash as the file prefix has already
2818//       been released.  Need to fix this.
2819//      mem_report("end.mem");
2820
2821//      jmalloc_uninit();
2822        l_user_stack.clean_up();
2823        l_ptr_stack.clean_up();
2824
2825        sound_uninit();
2826
2827        exit(0);
2828
2829        return 0;
2830}
2831
2832
Note: See TracBrowser for help on using the repository browser.