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

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