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

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