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

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