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

Last change on this file since 544 was 544, checked in by Sam Hocevar, 10 years ago

imlib: get rid of fast path loading, it was no longer used. We also
delete the old cache file we put in the user's directory.

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