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

Last change on this file since 656 was 656, checked in by Sam Hocevar, 11 years ago

imlib: move generic code back into the platform-agnostic imlib.

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