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

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