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

Last change on this file since 491 was 491, checked in by Sam Hocevar, 12 years ago

lisp: miscellaneous work on type safety.

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