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

Last change on this file since 576 was 576, checked in by Sam Hocevar, 8 years ago

game: properly time the fade in and fade out effects, as well as the
introduction scrolling.

File size: 67.4 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// Enabled TCPIP driver
87#if !defined __CELLOS_LV2__
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->set_mouse_shape(cache.img(c_target)->copy(), 8, 8);
446    else
447        wm->set_mouse_shape(cache.img(c_normal)->copy(), 1, 1);
448
449    if(old_state == SCENE_STATE && new_state != SCENE_STATE)
450    {
451        d = 1;
452        scene_director.set_abort(0);   // don't skip any more scene stuff
453    }
454    else if(new_state == SCENE_STATE && old_state != SCENE_STATE)
455        d = 1;
456
457    if(d)
458        draw(state == SCENE_STATE);
459
460    dev_cont->set_state(new_state);
461}
462
463void Game::joy_calb(event &ev)
464{
465    if(!joy_win) // make sure the 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->screen->bar(dx, dy, dx + jim->Size().x+6, dy + jim->Size().y+6, wm->black());
479        jim->put_image(joy_win->screen, dx + 3, dy + 3);
480
481        if(but)
482            joy_calibrate();
483    }
484    else if(ev.type == EV_MESSAGE && ev.message.id == JOY_OK)
485    {
486        wm->close_window(joy_win);
487        joy_win = NULL;
488        set_state(MENU_STATE);
489    }
490}
491
492void Game::menu_select(event &ev)
493{
494    state = DEV_MOUSE_RELEASE;
495    if(top_menu)
496    {
497#if 0
498        wm->push_event(new event(men_mess[((pick_list *)ev.message.data)->get_selection()], NULL));
499        wm->close_window(top_menu);
500        top_menu = NULL;
501#endif
502    }
503}
504
505
506void Game::show_help(char const *st)
507{
508    strcpy(help_text, st);
509    help_text_frames = 0;
510    refresh = 1;
511}
512
513void Game::draw_value(image *screen, int x, int y, int w, int h,
514                      int val, int max)
515{
516    screen->bar(x, y, x + w - 1, y + h, wm->dark_color());
517    screen->bar(x, y + 1, x + w * val / max, y + h - 1, wm->bright_color());
518}
519
520
521void Game::set_level(level *nl)
522{
523    if(current_level)
524        delete current_level;
525    current_level = nl;
526}
527
528void Game::load_level(char const *name)
529{
530    if(current_level)
531      delete current_level;
532
533    bFILE *fp = open_file(name, "rb");
534
535    if(fp->open_failure())
536    {
537        delete fp;
538        current_level = new level(100, 100, name);
539        char msg[100];
540        sprintf(msg, symbol_str("no_file"), name);
541        show_help(msg);
542    }
543    else
544    {
545        spec_directory sd(fp);
546        current_level = new level(&sd, fp, name);
547        delete fp;
548    }
549
550#if !defined __CELLOS_LV2__
551    base->current_tick=(current_level->tick_counter()&0xff);
552#endif
553
554    current_level->level_loaded_notify();
555    the_game->help_text_frames = 0;
556}
557
558int Game::done()
559{
560  return finished || (main_net_cfg && main_net_cfg->restart_state());
561}
562
563void Game::end_session()
564{
565  finished = true;
566  if(main_net_cfg)
567  {
568    delete main_net_cfg;
569    main_net_cfg = NULL;
570  }
571}
572
573void Game::put_block_fg(int x, int y, TransImage *im)
574{
575  for(view *f = first_view; f; f = f->next)
576  {
577    if(f->drawable())
578    {
579      int xoff = f->xoff(), yoff = f->yoff(), viewx1 = f->cx1, viewy1 = f->cy1, viewx2 = f->cx2, viewy2 = f->cy2;
580      if(xoff / ftile_width()>x || xoff / ftile_width()+(viewx2 - viewx1)/ftile_width()+1 < x ||
581      yoff / ftile_height()>y || yoff / ftile_height()+(viewy2 - viewy1)/ftile_height()+1 < y) return;
582      int cx1, cy1, cx2, cy2;
583      screen->GetClip(cx1, cy1, cx2, cy2);
584      screen->SetClip(viewx1, viewy1, viewx2 + 1, viewy2 + 1);
585      im->PutImage(screen, vec2i((x - xoff / ftile_width())*ftile_width()+viewx1 - xoff % ftile_width(),
586            (y - yoff / ftile_height())*ftile_height()+viewy1 - yoff % ftile_height()));
587      screen->SetClip(cx1, cy1, cx2, cy2);
588    }
589  }
590}
591
592void Game::put_block_bg(int x, int y, image *im)
593{
594  for(view *f = first_view; f; f = f->next)
595  {
596    if(f->drawable())
597    {
598      int xoff = f->xoff(), yoff = f->yoff(), viewx1 = f->cx1, viewy1 = f->cy1, viewx2 = f->cx2, viewy2 = f->cy2;
599      int xo = xoff * bg_xmul / bg_xdiv;
600      int yo = yoff * bg_ymul / bg_ydiv;
601
602      if(xo / btile_width()>x || xo / btile_width()+(viewx2 - viewx1)/btile_width()+1 < x ||
603      yo / btile_height()>y || yo / btile_height()+(viewy2 - viewy1)/btile_height()+1 < y) return;
604      int cx1, cy1, cx2, cy2;
605      screen->GetClip(cx1, cy1, cx2, cy2);
606      screen->SetClip(viewx1, viewy1, viewx2 + 1, viewy2 + 1);
607      im->put_image(screen, (x - xo / btile_width())*btile_width()+viewx1 - xo % btile_width(),
608            (y - yo / btile_height())*btile_height()+viewy1 - yo % btile_height(), 0);
609      screen->SetClip(cx1, cy1, cx2, cy2);
610    }
611  }
612}
613
614int need_delay = 1;
615
616void Game::dev_scroll()
617{
618  need_delay = 0;
619  if(dev)
620  {
621    int xmargin, ymargin;
622    if(xres > 400)
623    {
624      xmargin = 20;
625      ymargin = 10;
626    }
627    else
628    {
629      xmargin = 10;
630      ymargin = 5;
631    }
632
633    int xs, ys;
634    if(mousex < xmargin &&  dev_cont->ok_to_scroll()) xs = -18;
635    else if(mousex>(screen->Size().x-xmargin) &&  dev_cont->ok_to_scroll()) xs = 18;
636    else if(wm->key_pressed(JK_LEFT) && !last_input && !dev_cont->need_arrows())
637      xs = -18;
638    else if(wm->key_pressed(JK_RIGHT) && !last_input && !dev_cont->need_arrows())
639      xs = 18;
640    else xs = 0;
641
642
643    if(mousey < ymargin && dev_cont->ok_to_scroll()) ys = -18;
644    else if(mousey>(screen->Size().y-ymargin) &&  dev_cont->ok_to_scroll()) ys = 18;
645    else if(wm->key_pressed(JK_UP) && !last_input)
646      ys = -18;
647    else if(wm->key_pressed(JK_DOWN) && !last_input)
648      ys = 18;
649    else ys = 0;
650
651
652    if(xs || ys)
653    {
654      need_delay = 1;
655      if(dev & MAP_MODE)
656      {
657    map_xoff += xs / 2;
658    map_yoff += ys / 2;
659    if(map_xoff < 0) map_xoff = 0;
660    if(map_yoff < 0) map_yoff = 0;
661      }
662      else
663      {
664    for(view *v = first_view; v; v = v->next)
665    {
666      if(xs >= 0 || v->xoff()>0)
667        v->pan_x += xs;
668      if(ys >= 0 || v->yoff()>0)
669        v->pan_y += ys;
670    }
671      }
672      refresh = 1;
673    }
674  }
675}
676
677void remap_area(image *screen, int x1, int y1, int x2, int y2, uint8_t *remap)
678{
679    screen->Lock();
680
681    uint8_t *sl = (uint8_t *)screen->scan_line(y1) + x1;
682    int step = screen->Size().x - (x2 - x1 + 1);
683
684    for(int y = y1; y <= y2; y++)
685    {
686        for(int x = x1; x <= x2; x++)
687        {
688            uint8_t c = *sl;
689            *(sl++) = remap[c];
690        }
691        sl += step;
692    }
693    screen->Unlock();
694}
695
696static void post_render()
697{
698  if(DEFINEDP(l_post_render->GetFunction()))
699  {
700    screen->dirt_off();
701    clear_tmp();
702    l_post_render->EvalFunction(NULL);
703    clear_tmp();
704    screen->dirt_on();
705  }
706}
707
708void Game::draw_map(view *v, int interpolate)
709{
710  backtile *bt;
711  int x1, y1, x2, y2, x, y, xo, yo, nxoff, nyoff;
712  int cx1, cy1, cx2, cy2;
713  screen->GetClip(cx1, cy1, cx2, cy2);
714
715  if(!current_level || state == MENU_STATE)
716  {
717    if(title_screen >= 0)
718    {
719      if(state == SCENE_STATE)
720        screen->SetClip(v->cx1, v->cy1, v->cx2 + 1, v->cy2 + 1);
721      image *tit = cache.img(title_screen);
722      tit->put_image(screen, screen->Size().x/2 - tit->Size().x/2,
723                    screen->Size().y/2 - tit->Size().y/2);
724      if(state == SCENE_STATE)
725        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    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    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    screen->Lock();
746    for(int y = v->cy1; y <= v->cy2; y++)
747      memset(screen->scan_line(y)+v->cx1, c, v->cx2 - v->cx1 + 1);
748    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 = screen;
768    screen = small_render;
769  } else
770    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  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        bt->im->put_image(screen, 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    screen->GetClip(ncx1, ncy1, ncx2, ncy2);
893
894    int scr_w = screen->Size().x;
895    if(dev & MAP_MODE)
896    {
897      if(dev & EDIT_MODE)
898        screen->clear(wm->bright_color());
899      else
900        screen->clear(wm->black());
901      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 = 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      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(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(screen, vec2i(draw_x, draw_y));
997          else
998          get_fg(fort_num)->im->PutFilled(screen, vec2i(draw_x, draw_y), 0);
999
1000          if(!(dev & EDIT_MODE))
1001          current_level->mark_seen(x, y);
1002          else
1003          {
1004        screen->line(draw_x, draw_y, draw_x + xinc, draw_y + yinc, wm->bright_color());
1005        screen->line(draw_x + xinc, draw_y, 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          screen->line(draw_x+*(d - 2), draw_y+*(d - 1), draw_x+*d, draw_y+*(d + 1), b);
1040        }
1041        screen->line(draw_x+*d, draw_y+*(d - 1), draw_x + p->data[0], draw_y + p->data[1], b);
1042          }
1043        }
1044      }
1045    }
1046      }
1047    }
1048
1049//    if(!(dev & EDIT_MODE))
1050//      server_check();
1051
1052    if(dev & DRAW_HELP_LAYER)
1053    {
1054      if(help_text_frames >= 0)
1055      {
1056    int color;
1057
1058    if(help_text_frames < 10)
1059        color = 2;
1060    else
1061        color = 2+(help_text_frames - 10);
1062
1063    int x1 = v->cx1, y1 = v->cy1, x2 = v->cx2, y2 = v->cy1 + wm->font()->height()+10;
1064
1065    remap_area(screen, x1, y1, x2, y2, white_light + 40 * 256);
1066    screen->bar(x1, y1, x2, y1, color);
1067    screen->bar(x1, y2, x2, y2, color);
1068
1069    wm->font()->put_string(screen, x1 + 5, y1 + 5,
1070                   help_text, color);
1071    if(color > 30)
1072        help_text_frames = -1;
1073    else help_text_frames++;
1074
1075      }
1076    }
1077
1078    if(dev_cont)
1079    dev_cont->dev_draw(v);
1080    if(cache.in_use())
1081    cache.img(vmm_image)->put_image(screen, v->cx1, v->cy2 - cache.img(vmm_image)->Size().y+1);
1082
1083    if(dev & DRAW_LIGHTS)
1084    {
1085      if(small_render)
1086      {
1087    double_light_screen(screen, xoff, yoff, white_light, v->ambient, old_screen, old_cx1, old_cy1);
1088
1089    v->cx1 = old_cx1;
1090    v->cy1 = old_cy1;
1091    v->cx2 = old_cx2;
1092    v->cy2 = old_cy2;
1093    screen = old_screen;
1094      } else
1095      {
1096    screen->dirt_on();
1097    if(xres * yres <= 64000)
1098          light_screen(screen, xoff, yoff, white_light, v->ambient);
1099    else light_screen(screen, xoff, yoff, white_light, 63);            // no lighting for hi - rez
1100      }
1101
1102    } else
1103      screen->dirt_on();
1104
1105
1106
1107  }  else
1108    screen->dirt_on();
1109
1110  rand_on = ro;                // restore random start in case in draw funs moved it
1111                               // ... not every machine will draw the same thing
1112
1113  post_render();
1114
1115  screen->SetClip(cx1, cy1, cx2 + 1, cy2 + 1);
1116
1117
1118
1119
1120  if(playing_state(state))        // draw stuff outside the clipping region
1121    v->draw_character_damage();
1122
1123  if(profiling())
1124    profile_update();
1125
1126  sbar.draw_update();
1127}
1128
1129void Game::put_fg(int x, int y, int type)
1130{
1131  if(current_level->get_fg(x, y)!=type)
1132  {
1133    current_level->put_fg(x, y, type);
1134    for(view *f = first_view; f; f = f->next)
1135      if(f->drawable())
1136        draw_map(f);
1137  }
1138}
1139
1140void Game::put_bg(int x, int y, int type)
1141{
1142  if(current_level->get_bg(x, y)!=type)
1143  {
1144    current_level->put_bg(x, y, type);
1145    for(view *f = first_view; f; f = f->next)
1146      if(f->drawable())
1147        draw_map(f);
1148  }
1149}
1150
1151int Game::in_area(event &ev, int x1, int y1, int x2, int y2)
1152{
1153  return (last_demo_mx >= x1 && last_demo_mx <= x2 &&
1154      last_demo_my >= y1 && last_demo_my <= y2);
1155}
1156
1157void Game::request_level_load(char *name)
1158{
1159  strcpy(req_name, name);
1160}
1161
1162extern int start_doubled;
1163
1164template<int N> static void Fade(image *im, int steps)
1165{
1166    /* 25ms per step */
1167    float const duration = 25.f;
1168
1169    palette *old_pal = pal->copy();
1170
1171    if (im)
1172    {
1173        screen->clear();
1174        im->put_image(screen, (xres + 1) / 2 - im->Size().x / 2,
1175                              (yres + 1) / 2 - im->Size().y / 2);
1176    }
1177
1178    for (Timer total; total.PollMs() < duration * steps; )
1179    {
1180        Timer frame;
1181        uint8_t *sl1 = (uint8_t *)pal->addr();
1182        uint8_t *sl2 = (uint8_t *)old_pal->addr();
1183        int i = (int)(total.PollMs() / duration);
1184        int v = (N ? i + 1 : steps - i) * 256 / steps;
1185
1186        for (int j = 0; j < 3 * 256; j++)
1187            *sl1++ = (int)*sl2++ * v / 256;
1188
1189        pal->load();
1190        wm->flush_screen();
1191        frame.WaitMs(duration);
1192    }
1193
1194    if (N == 0)
1195    {
1196        screen->clear();
1197        wm->flush_screen();
1198        old_pal->load();
1199    }
1200    delete pal;
1201    pal = old_pal;
1202}
1203
1204void fade_in(image *im, int steps)
1205{
1206    Fade<1>(im, steps);
1207}
1208
1209void fade_out(int steps)
1210{
1211    Fade<0>(NULL, steps);
1212}
1213
1214int text_draw(int y, int x1, int y1, int x2, int y2, char const *buf, JCFont *font, uint8_t *cmap, char color);
1215
1216void do_title()
1217{
1218    if(cdc_logo == -1)
1219        return;
1220
1221    if(sound_avail & MUSIC_INITIALIZED)
1222    {
1223        if(current_song)
1224        {
1225            current_song->stop();
1226            delete current_song;
1227        }
1228        current_song = new song("music/intro.hmi");
1229        current_song->play(music_volume);
1230    }
1231
1232    void *logo_snd = LSymbol::FindOrCreate("LOGO_SND")->GetValue();
1233
1234    if(DEFINEDP(logo_snd) && (sound_avail & SFX_INITIALIZED))
1235        cache.sfx(lnumber_value(logo_snd))->play(sfx_volume);
1236
1237    // This must be a dynamic allocated image because if it
1238    // is not and the window gets closed during do_title, then
1239    // exit() will try to delete (through the desctructor of
1240    // image_list in image.cpp) the image on the stack -> boom.
1241    image *blank = new image(vec2i(2, 2));
1242    blank->clear();
1243    wm->set_mouse_shape(blank->copy(), 0, 0); // hide mouse
1244    delete blank;
1245    fade_in(cache.img(cdc_logo), 32);
1246
1247    milli_wait(400);
1248
1249    void *space_snd = LSymbol::FindOrCreate("SPACE_SND")->GetValue();
1250
1251    fade_out(32);
1252    milli_wait(100);
1253
1254    char *str = lstring_value(LSymbol::FindOrCreate("plot_start")->Eval());
1255
1256    bFILE *fp = open_file("art/smoke.spe", "rb");
1257    if(!fp->open_failure())
1258    {
1259        spec_directory sd(fp);
1260        palette *old_pal = pal;
1261        pal = new palette(sd.find(SPEC_PALETTE), fp);
1262        pal->shift(1);
1263
1264        image *gray = new image(fp, sd.find("gray_pict"));
1265        image *smoke[5];
1266
1267        char nm[20];
1268        for (int i = 0; i < 5; i++)
1269        {
1270            sprintf(nm, "smoke%04d.pcx", i + 1);
1271            smoke[i] = new image(fp, sd.find(nm));
1272        }
1273
1274        screen->clear();
1275        pal->load();
1276
1277        int dx = (xres + 1) / 2 - gray->Size().x / 2, dy = (yres + 1) / 2 - gray->Size().y / 2;
1278        gray->put_image(screen, dx, dy);
1279        smoke[0]->put_image(screen, dx + 24, dy + 5);
1280
1281        fade_in(NULL, 16);
1282        uint8_t cmap[32];
1283        for(int i = 0; i < 32; i++)
1284        cmap[i] = pal->find_closest(i * 256 / 32, i * 256 / 32, i * 256 / 32);
1285
1286        event ev;
1287        ev.type = EV_SPURIOUS;
1288        Timer total;
1289
1290        while (ev.type != EV_KEY && ev.type != EV_MOUSE_BUTTON)
1291        {
1292            Timer frame;
1293
1294            // 100 ms per step
1295            int i = (int)(total.PollMs() / 100.f);
1296            if (i >= 320)
1297                break;
1298
1299            gray->put_image(screen, dx, dy);
1300            smoke[i % 5]->put_image(screen, dx + 24, dy + 5);
1301            text_draw(205 - i, dx + 15, dy, dx + 320 - 15, dy + 199, str, wm->font(), cmap, wm->bright_color());
1302            wm->flush_screen();
1303            time_marker now;
1304
1305            while(wm->event_waiting() && ev.type != EV_KEY)
1306                wm->get_event(ev);
1307
1308            if((i % 5) == 0 && DEFINEDP(space_snd) && (sound_avail & SFX_INITIALIZED))
1309                cache.sfx(lnumber_value(space_snd))->play(sfx_volume * 90 / 127);
1310
1311            frame.WaitMs(25.f);
1312        }
1313
1314        the_game->reset_keymap();
1315
1316        fade_out(16);
1317
1318        for (int i = 0; i < 5; i++)
1319            delete smoke[i];
1320        delete gray;
1321        delete pal;
1322        pal = old_pal;
1323    }
1324    delete fp;
1325
1326    if(title_screen >= 0)
1327        fade_in(cache.img(title_screen), 32);
1328}
1329
1330extern int start_edit;
1331
1332void Game::request_end()
1333{
1334  req_end = 1;
1335}
1336
1337Game::Game(int argc, char **argv)
1338{
1339  int i;
1340  req_name[0]=0;
1341  bg_xmul = bg_ymul = 1;
1342  bg_xdiv = bg_ydiv = 8;
1343  last_input = NULL;
1344  current_automap = NULL;
1345  current_level = NULL;
1346  refresh = 1;
1347  the_game = this;
1348  top_menu = joy_win = NULL;
1349  old_view = first_view = NULL;
1350  nplayers = 1;
1351
1352  help_text_frames = 0;
1353  strcpy(help_text, "");
1354
1355
1356  for(i = 1; i < argc; i++)
1357    if(!strcmp(argv[i], "-no_delay"))
1358    {
1359      no_delay = 1;
1360      dprintf("Frame delay off (-nodelay)\n");
1361    }
1362
1363
1364  image_init();
1365  zoom = 15;
1366  no_delay = 0;
1367
1368  if(get_option("-use_joy"))
1369  {
1370    has_joystick = joy_init(argc, argv);
1371    dprintf("Joystick : ");
1372    if(has_joystick) dprintf("detected\n");
1373    else dprintf("not detected\n");
1374  }
1375  else has_joystick = 0;
1376
1377    // Clean up that old crap
1378    char *fastpath = (char *)malloc(strlen(get_save_filename_prefix()) + 13);
1379    sprintf(fastpath, "%sfastload.dat", get_save_filename_prefix());
1380    unlink(fastpath);
1381    free(fastpath);
1382
1383//    ProfilerInit(collectDetailed, bestTimeBase, 2000, 200); //prof
1384    load_data(argc, argv);
1385//    ProfilerDump("\pabuse.prof");  //prof
1386//    ProfilerTerm();
1387
1388  get_key_bindings();
1389
1390  reset_keymap();                   // we think all the keys are up right now
1391  finished = false;
1392
1393  calc_light_table(pal);
1394
1395#if !defined __CELLOS_LV2__
1396  if(current_level == NULL && net_start())  // if we joined a net game get level from server
1397  {
1398    if(!request_server_entry())
1399    {
1400      exit(0);
1401    }
1402    net_reload();
1403//    load_level(NET_STARTFILE);
1404  }
1405#endif
1406
1407  set_mode(19, argc, argv);
1408  if(get_option("-2") && (xres < 639 || yres < 399))
1409  {
1410    close_graphics();
1411    fprintf(stderr, "Resolution must be > 640x400 to use -2 option\n");
1412    exit(0);
1413  }
1414  pal->load();
1415
1416  recalc_local_view_space();   // now that we know what size the screen is...
1417
1418  dark_color = get_color(cache.img(window_colors)->Pixel(vec2i(2, 0)));
1419  bright_color = get_color(cache.img(window_colors)->Pixel(vec2i(0, 0)));
1420  med_color = get_color(cache.img(window_colors)->Pixel(vec2i(1, 0)));
1421
1422  morph_dark_color = get_color(cache.img(window_colors)->Pixel(vec2i(2, 1)));
1423  morph_bright_color = get_color(cache.img(window_colors)->Pixel(vec2i(0, 1)));
1424  morph_med_color = get_color(cache.img(window_colors)->Pixel(vec2i(1, 1)));
1425  morph_sel_frame_color = pal->find_closest(255, 255, 0);
1426  light_connection_color = morph_sel_frame_color;
1427
1428  if(NILP(symbol_value(l_default_font)))
1429  {
1430    printf("No font defined, set symbol default-font to an image name\n");
1431    exit(0);
1432  }
1433  int font_pict;
1434  if(big_font_pict != -1)
1435  {
1436    if(small_font_pict != -1)
1437    {
1438      if(xres/(start_doubled ? 2 : 1)>400)
1439      {
1440    font_pict = big_font_pict;
1441      }
1442      else font_pict = small_font_pict;
1443    } else font_pict = big_font_pict;
1444  } else font_pict = small_font_pict;
1445
1446  if(console_font_pict == -1) console_font_pict = font_pict;
1447  game_font = new JCFont(cache.img(font_pict));
1448
1449  console_font = new JCFont(cache.img(console_font_pict));
1450
1451  wm = new WindowManager(screen, pal, bright_color,
1452                         med_color, dark_color, game_font);
1453
1454  delete stat_man;  // move to a graphical status manager
1455  gui_status_manager *gstat = new gui_status_manager();
1456  gstat->set_window_title("status");
1457  stat_man = gstat;
1458
1459
1460  chat = new chat_console( console_font, 50, 6);
1461
1462  if(!wm->has_mouse())
1463  {
1464    close_graphics();
1465    image_uninit();
1466    printf("No mouse driver detected, please rectify.\n");
1467    exit(0);
1468  }
1469
1470
1471  gamma_correct(pal);
1472
1473#if defined __CELLOS_LV2__
1474  if(!start_edit)
1475    do_title();
1476#else
1477  if(main_net_cfg == NULL || (main_net_cfg->state != net_configuration::SERVER &&
1478                 main_net_cfg->state != net_configuration::CLIENT))
1479  {
1480    if(!start_edit && !net_start())
1481      do_title();
1482  } else if(main_net_cfg && main_net_cfg->state == net_configuration::SERVER)
1483  {
1484    the_game->load_level(level_file);
1485    start_running = 1;
1486  }
1487#endif
1488
1489
1490  dev|= DRAW_FG_LAYER | DRAW_BG_LAYER | DRAW_PEOPLE_LAYER | DRAW_HELP_LAYER | DRAW_LIGHTS | DRAW_LINKS;
1491
1492  if(dev & EDIT_MODE)
1493    set_frame_size(0);
1494//  do_intro();
1495  state = START_STATE;         // first set the state to one that has windows
1496
1497
1498  if(start_running)
1499    set_state(RUN_STATE);
1500  else
1501  {
1502    screen->clear();
1503    if(title_screen >= 0)
1504    {
1505      image *tit = cache.img(title_screen);
1506      tit->put_image(screen, screen->Size().x/2 - tit->Size().x/2,
1507                    screen->Size().y/2 - tit->Size().y/2);
1508    }
1509    set_state(MENU_STATE);   // then go to menu state so windows will turn off
1510  }
1511}
1512
1513
1514
1515time_marker *led_last_time = NULL, *fps_mark_start = NULL;
1516double avg_fps = 15.0, possible_fps = 15.0;
1517
1518void Game::toggle_delay()
1519{
1520  no_delay=!no_delay;
1521  if(no_delay)
1522    show_help(symbol_str("delay_off"));
1523  else show_help(symbol_str("delay_on"));
1524  avg_fps = possible_fps = 15.0;
1525}
1526
1527void Game::show_time()
1528{
1529  if(first_view && fps_on)
1530  {
1531    char str[10];
1532    sprintf(str, "%ld", (long)(avg_fps * 10.0));
1533    console_font->put_string(screen, first_view->cx1, first_view->cy1, str);
1534
1535    sprintf(str, "%d", total_active);
1536    console_font->put_string(screen, first_view->cx1, first_view->cy1 + 10, str);
1537  }
1538}
1539
1540void Game::update_screen()
1541{
1542  if(state == HELP_STATE)
1543    draw_help();
1544  else if(current_level)
1545  {
1546    if(!(dev & EDIT_MODE) || refresh)
1547    {
1548      view *f = first_view;
1549      current_level->clear_active_list();
1550      for(; f; f = f->next)
1551      {
1552    if(f->focus)
1553    {
1554      int w, h;
1555
1556      w=(f->cx2 - f->cx1 + 1);
1557      h=(f->cy2 - f->cy1 + 1);
1558
1559      total_active += current_level->add_drawables(f->xoff()-w / 4, f->yoff()-h / 4,
1560                             f->xoff()+w + w / 4, f->yoff()+h + h / 4);
1561
1562    }
1563      }
1564
1565      for(f = first_view; f; f = f->next)
1566      {
1567        if(f->drawable())
1568    {
1569      if(interpolate_draw)
1570      {
1571            draw_map(f, 1);
1572        wm->flush_screen();
1573      }
1574          draw_map(f, 0);
1575    }
1576      }
1577      if(current_automap)
1578      current_automap->draw();
1579    }
1580    if(state == PAUSE_STATE)
1581    {
1582      for(view *f = first_view; f; f = f->next)
1583        cache.img(pause_image)->put_image(screen, (f->cx1 + f->cx2)/2 - cache.img(pause_image)->Size().x/2,
1584                   f->cy1 + 5, 1);
1585    }
1586
1587    show_time();
1588  }
1589
1590  if(state == RUN_STATE && cache.prof_is_on())
1591    cache.prof_poll_end();
1592
1593  wm->flush_screen();
1594
1595}
1596
1597void Game::do_intro()
1598{
1599
1600}
1601
1602int Game::calc_speed()
1603{
1604    int ret = 0;
1605    if(fps_mark_start)
1606    {
1607        time_marker t;
1608
1609        // find average fps for last 10 frames
1610        double td = t.diff_time(fps_mark_start);
1611        if(td < 0.001)     // something is rotten in the state of demark
1612            td = 0.001;
1613
1614        avg_fps = avg_fps * 9.0 / 10.0 + 1.0/(td * 10.0);
1615        possible_fps = possible_fps * 9.0 / 10.0 + 1.0/(td * 10.0);
1616
1617        if(avg_fps > 14)
1618        {
1619            if(massive_frame_panic > 20)
1620                massive_frame_panic = 20;
1621            else if(massive_frame_panic)
1622                massive_frame_panic--;
1623        }
1624
1625        if(avg_fps > 15 && ((dev & EDIT_MODE)==0 || need_delay))
1626        {
1627            frame_panic = 0;
1628            int32_t stime=(int32_t)((1 / 15.0 - 1.0 / possible_fps)*1000.0);
1629            if(stime > 0 && !no_delay)
1630            {
1631                milli_wait(stime);
1632                avg_fps -= 1.0/(td * 10.0);   // subtract out old estimate
1633
1634                time_marker t;
1635
1636                // find average fps for last 10 frames
1637                double td = t.diff_time(fps_mark_start);
1638                if(td < 0.00001)     // something is rotten in the state of demark
1639                    td = 0.00001;
1640
1641                avg_fps += 1.0/(td * 10.0);       // add in new estimate
1642            }
1643        }
1644        else if(avg_fps < 14)
1645        {
1646            if(avg_fps < 10)
1647                massive_frame_panic++;
1648            frame_panic++;
1649            ret = 1;
1650        }
1651        else if(dev & EDIT_MODE)
1652        {
1653            // ECS - Added this case and the wait.  It's a cheap hack to assure that
1654            // we don't exceed 30FPS in edit mode and hog the CPU.
1655            milli_wait(33);
1656        }
1657
1658        delete fps_mark_start;
1659    }
1660    fps_mark_start = new time_marker;
1661    return ret;
1662}
1663
1664extern int start_edit;
1665
1666void Game::get_input()
1667{
1668    event ev;
1669    idle_ticks++;
1670    while(event_waiting())
1671    {
1672        get_event(ev);
1673
1674        if(ev.type == EV_MOUSE_MOVE)
1675        {
1676            last_input = ev.window;
1677        }
1678        // don't process repeated keys in the main window, it will slow down the game to handle such
1679        // useless events. However in other windows it might be useful, such as in input windows
1680        // where you want to repeatedly scroll down...
1681        if(ev.type != EV_KEY || !key_down(ev.key) || ev.window || (dev & EDIT_MODE))
1682        {
1683#if !defined __CELLOS_LV2__
1684            if(ev.type == EV_KEY)
1685            {
1686                set_key_down(ev.key, 1);
1687                if(playing_state(state))
1688                {
1689                    if(ev.key < 256)
1690                    {
1691                        if(chat && chat->chat_event(ev))
1692                            base->packet.write_uint8(SCMD_CHAT_KEYPRESS);
1693                        else
1694                            base->packet.write_uint8(SCMD_KEYPRESS);
1695                    }
1696                    else
1697                        base->packet.write_uint8(SCMD_EXT_KEYPRESS);
1698                    base->packet.write_uint8(client_number());
1699                    if(ev.key > 256)
1700                        base->packet.write_uint8(ev.key - 256);
1701                    else
1702                        base->packet.write_uint8(ev.key);
1703                }
1704            }
1705            else if(ev.type == EV_KEYRELEASE)
1706            {
1707                set_key_down(ev.key, 0);
1708                if(playing_state(state))
1709                {
1710                    if(ev.key < 256)
1711                        base->packet.write_uint8(SCMD_KEYRELEASE);
1712                    else
1713                        base->packet.write_uint8(SCMD_EXT_KEYRELEASE);
1714                    base->packet.write_uint8(client_number());
1715                    if(ev.key > 255)
1716                        base->packet.write_uint8(ev.key - 256);
1717                    else
1718                        base->packet.write_uint8(ev.key);
1719                }
1720            }
1721#endif
1722
1723            if((dev & EDIT_MODE) || start_edit || ev.type == EV_MESSAGE)
1724            {
1725                dev_cont->handle_event(ev);
1726            }
1727
1728            view *v = first_view;
1729            for(; v; v = v->next)
1730            {
1731                if(v->local_player() && v->handle_event(ev))
1732                    ev.type = EV_SPURIOUS;       // if the event was used by the view, gobble it up
1733            }
1734
1735            if(current_automap)
1736            {
1737                current_automap->handle_event(ev);
1738            }
1739
1740            help_handle_event(ev);
1741            mousex = last_demo_mx;
1742            mousey = last_demo_my;
1743
1744            if(ev.type == EV_MESSAGE)
1745            {
1746                switch (ev.message.id)
1747                {
1748                    case CALB_JOY:
1749                    {
1750                        if(!joy_win)
1751                        {
1752                            joy_win = wm->new_window(80, 50, -1, -1,
1753                                    new button(70, 9, JOY_OK, "OK",
1754                                    new info_field(0, 30, DEV_NULL,
1755                                    " Center joystick and\n"
1756                                    "press the fire button", NULL)),
1757                                    "Joystick");
1758                            set_state(JOY_CALB_STATE);
1759                        }
1760                    }
1761                    case TOP_MENU:
1762                    {
1763                        menu_select(ev);
1764                    } break;
1765                    case DEV_QUIT:
1766                    {
1767                        finished = true;
1768                    } break;
1769                }
1770            }
1771            else if(ev.type == EV_CLOSE_WINDOW && ev.window == top_menu)
1772            {
1773                wm->close_window(top_menu);
1774                top_menu = NULL;
1775            }
1776
1777            switch(state)
1778            {
1779                case JOY_CALB_STATE:
1780                {
1781                    joy_calb(ev);
1782                } break;
1783                case INTRO_START_STATE:
1784                {
1785                    do_intro();
1786                    if(dev & EDIT_MODE)
1787                        set_state(RUN_STATE);
1788                    else
1789                        set_state(MENU_STATE);
1790                } break;
1791                case PAUSE_STATE:
1792                {
1793                    if(ev.type == EV_KEY && (ev.key == JK_SPACE || ev.key == JK_ENTER))
1794                    {
1795                        set_state(RUN_STATE);
1796                    }
1797                } break;
1798                case RUN_STATE:
1799                {
1800                    if(ev.window == NULL)
1801                    {
1802                        switch (ev.type)
1803                        {
1804                            case EV_KEY:
1805                            {
1806                                switch (ev.key)
1807                                {
1808                                    case 'm':
1809                                    {
1810                                        if(dev & MAP_MODE)
1811                                            dev -= MAP_MODE;
1812                                        else if((player_list && player_list->next) || dev & EDIT_MODE)
1813                                            dev |= MAP_MODE;
1814
1815                                        if(!(dev & MAP_MODE))
1816                                        {
1817                                            if(dev_cont->tbw)
1818                                                dev_cont->toggle_toolbar();
1819                                            edit_mode = ID_DMODE_DRAW;
1820                                        }
1821                                        need_refresh();
1822                                    } break;
1823                                    case 'v':
1824                                    {
1825                                        wm->push_event(new event(DO_VOLUME, NULL));
1826                                    } break;
1827                                    case 'p':
1828                                    {
1829                                        if(!(dev & EDIT_MODE) && (!main_net_cfg ||
1830                                            (main_net_cfg->state != net_configuration::SERVER &&
1831                                            main_net_cfg->state != net_configuration::CLIENT)))
1832                                        {
1833                                            set_state(PAUSE_STATE);
1834                                        }
1835                                    } break;
1836                                    case 'S':
1837                                    {
1838                                        if(start_edit)
1839                                        {
1840                                            wm->push_event(new event(ID_LEVEL_SAVE, NULL));
1841                                        }
1842                                    } break;
1843                                    case JK_TAB:
1844                                        if(start_edit)
1845                                            toggle_edit_mode();
1846                                        need_refresh();
1847                                        break;
1848                                    case 'c':
1849                                    case 'C':
1850                                        if(chatting_enabled && (!(dev & EDIT_MODE) && chat))
1851                                            chat->toggle();
1852                                        break;
1853                                    case '9':
1854                                        dev = dev ^ PERFORMANCE_TEST_MODE;
1855                                        need_refresh();
1856                                        break;
1857                                }
1858                            } break;
1859                            case EV_RESIZE:
1860                            {
1861                                view *v;
1862                                for(v = first_view; v; v = v->next)  // see if any views need to change size
1863                                {
1864                                    if(v->local_player())
1865                                    {
1866                                        int w = (xres - 10)/(small_render ? 2 : 1);
1867                                        int h = (yres - 10)/(small_render ? 2 : 1);
1868
1869                                        v->suggest.send_view = 1;
1870                                        v->suggest.cx1 = 5;
1871                                        v->suggest.cx2 = 5 + w;
1872                                        v->suggest.cy1 = 5;
1873                                        v->suggest.cy2 = 5 + h;
1874                                        v->suggest.pan_x = v->pan_x;
1875                                        v->suggest.pan_y = v->pan_y;
1876                                        v->suggest.shift_down = v->shift_down;
1877                                        v->suggest.shift_right = v->shift_right;
1878                                    }
1879                                }
1880                                draw();
1881                            } break;
1882                            case EV_REDRAW:
1883                            {
1884                                screen->AddDirty(ev.redraw.x1, ev.redraw.y1,
1885                                    ev.redraw.x2 + 1, ev.redraw.y2 + 1);
1886                            } break;
1887                            case EV_MESSAGE:
1888                            {
1889                                switch (ev.message.id)
1890                                {
1891                                    case RAISE_SFX:
1892                                    case LOWER_SFX:
1893                                    case RAISE_MUSIC:
1894                                    case LOWER_MUSIC:
1895                                    {
1896                                        if(ev.message.id == RAISE_SFX && sfx_volume != 127)
1897                                            sfx_volume = Min(127, sfx_volume + 16);
1898                                        if(ev.message.id == LOWER_SFX && sfx_volume != 0)
1899                                            sfx_volume = Max(sfx_volume - 16, 0);
1900                                        if(ev.message.id == RAISE_MUSIC && music_volume != 126)
1901                                        {
1902                                            music_volume = Min(music_volume + 16, 127);
1903                                            if(current_song && (sound_avail & MUSIC_INITIALIZED))
1904                                                current_song->set_volume(music_volume);
1905                                        }
1906
1907                                        if(ev.message.id == LOWER_MUSIC && music_volume != 0)
1908                                        {
1909                                            music_volume = Max(music_volume - 16, 0);
1910                                            if(current_song && (sound_avail & MUSIC_INITIALIZED))
1911                                                current_song->set_volume(music_volume);
1912                                        }
1913
1914                                        ((button *)ev.message.data)->push();
1915/*                                        volume_window->inm->redraw();
1916                                        draw_value(volume_window->screen, 2, 43,
1917                                                (volume_window->x2()-volume_window->x1()-1), 8, sfx_volume, 127);
1918                                        draw_value(volume_window->screen, 2, 94,
1919                                                (volume_window->x2()-volume_window->x1()-1), 8, music_volume, 127);
1920*/
1921                                        break;
1922                                    }
1923                                }
1924                            }
1925                        }
1926                    }
1927                } break;
1928            }
1929        }
1930    }
1931}
1932
1933
1934void net_send(int force = 0)
1935{
1936#if !defined __CELLOS_LV2__
1937  if((!(dev & EDIT_MODE)) || force)
1938  {
1939    if(demo_man.state == demo_manager::PLAYING)
1940    {
1941      base->input_state = INPUT_PROCESSING;
1942    } else
1943    {
1944
1945
1946
1947      if(!player_list->focus)
1948      {
1949    dprintf("Players have not been created\ncall create_players");
1950    exit(0);
1951      }
1952
1953
1954      view *p = player_list;
1955      for(; p; p = p->next)
1956        if(p->local_player())
1957      p->get_input();
1958
1959
1960      base->packet.write_uint8(SCMD_SYNC);
1961      base->packet.write_uint16(make_sync());
1962
1963      if(base->join_list)
1964      base->packet.write_uint8(SCMD_RELOAD);
1965
1966      //      printf("save tick %d, pk size=%d, rand_on=%d, sync=%d\n", current_level->tick_counter(),
1967      //         base->packet.packet_size(), rand_on, make_sync());
1968      send_local_request();
1969    }
1970  }
1971#endif
1972}
1973
1974void net_receive()
1975{
1976#if !defined __CELLOS_LV2__
1977  if(!(dev & EDIT_MODE) && current_level)
1978  {
1979    uint8_t buf[PACKET_MAX_SIZE + 1];
1980    int size;
1981
1982    if(demo_man.state == demo_manager::PLAYING)
1983    {
1984      if(!demo_man.get_packet(buf, size))
1985        size = 0;
1986      base->packet.packet_reset();
1987      base->mem_lock = 0;
1988    } else
1989    {
1990      size = get_inputs_from_server(buf);
1991      if(demo_man.state == demo_manager::RECORDING)
1992    demo_man.save_packet(buf, size);
1993    }
1994
1995    process_packet_commands(buf, size);
1996  }
1997#endif
1998}
1999
2000void Game::step()
2001{
2002  clear_tmp();
2003  if(current_level)
2004  {
2005    current_level->unactivate_all();
2006    total_active = 0;
2007    for(view *f = first_view; f; f = f->next)
2008    {
2009      if(f->focus)
2010      {
2011    f->update_scroll();
2012    int w, h;
2013
2014    w=(f->cx2 - f->cx1 + 1);
2015    h=(f->cy2 - f->cy1 + 1);
2016        total_active += current_level->add_actives(f->xoff()-w / 4, f->yoff()-h / 4,
2017                         f->xoff()+w + w / 4, f->yoff()+h + h / 4);
2018      }
2019    }
2020  }
2021
2022  if(state == RUN_STATE)
2023  {
2024    if((dev & EDIT_MODE) || (main_net_cfg && (main_net_cfg->state == net_configuration::CLIENT ||
2025                         main_net_cfg->state == net_configuration::SERVER)))
2026      idle_ticks = 0;
2027
2028    if(demo_man.current_state()==demo_manager::NORMAL && idle_ticks > 420 && demo_start)
2029    {
2030      idle_ticks = 0;
2031      set_state(MENU_STATE);
2032    }
2033    else if(!(dev & EDIT_MODE))               // if edit mode, then don't step anything
2034    {
2035      if(key_down(JK_ESC))
2036      {
2037    set_state(MENU_STATE);
2038    set_key_down(JK_ESC, 0);
2039      }
2040      ambient_ramp = 0;
2041      view *v;
2042      for(v = first_view; v; v = v->next)
2043        v->update_scroll();
2044
2045      cache.prof_poll_start();
2046      current_level->tick();
2047      sbar.step();
2048    } else
2049      dev_scroll();
2050  } else if(state == JOY_CALB_STATE)
2051  {
2052    event ev;
2053    joy_calb(ev);
2054  } else if(state == MENU_STATE)
2055    main_menu();
2056
2057  if((key_down('x') || key_down(JK_F4))
2058      && (key_down(JK_ALT_L) || key_down(JK_ALT_R))
2059      && confirm_quit())
2060    finished = true;
2061}
2062
2063extern void *current_demo;
2064
2065Game::~Game()
2066{
2067  current_demo = NULL;
2068  if(first_view == player_list) first_view = NULL;
2069  while(player_list)
2070  {
2071    view *p = player_list;
2072    game_object *o = p->focus;
2073    player_list = player_list->next;
2074    delete p;
2075    o->set_controller(NULL);
2076    if(current_level && o)
2077      current_level->delete_object(o);
2078    else delete o;
2079  }
2080
2081  if(current_level) { delete current_level; current_level = NULL; }
2082
2083  if(first_view != player_list)
2084  {
2085    while(player_list)
2086    {
2087      view *p = player_list;
2088      player_list = player_list->next;
2089      delete p;
2090    }
2091  }
2092
2093  while(first_view)
2094  {
2095    view *p = first_view;
2096    first_view = first_view->next;
2097    delete p;
2098  }
2099
2100  player_list = NULL;
2101
2102  if(old_view)
2103  {
2104    first_view = old_view;
2105    while(first_view)
2106    {
2107      view *p = first_view;
2108      first_view = first_view->next;
2109      delete p;
2110    }
2111  }
2112  old_view = NULL;
2113
2114  int i = 0;
2115  for(; i < total_objects; i++)
2116  {
2117    free(object_names[i]);
2118    delete figures[i];
2119  }
2120  free_pframes();
2121  if(fps_mark_start) delete fps_mark_start; fps_mark_start = NULL;
2122  delete pal;
2123  free(object_names);
2124  free(figures);
2125
2126  free(backtiles);
2127  free(foretiles);
2128  if(total_weapons)
2129    free(weapon_types);
2130
2131  config_cleanup();
2132  delete color_table;
2133  delete wm;
2134  delete game_font;
2135  delete big_font;
2136  delete console_font;
2137  if(total_help_screens)
2138    free(help_screens);
2139
2140  close_graphics();
2141  image_uninit();
2142}
2143
2144
2145
2146void Game::draw(int scene_mode)
2147{
2148    screen->AddDirty(0, 0, xres + 1, yres + 1);
2149
2150    screen->clear();
2151
2152    if(scene_mode)
2153    {
2154        char const *helpstr = "ARROW KEYS CHANGE TEXT SPEED";
2155        wm->font()->put_string(screen, screen->Size().x/2-(wm->font()->width()*strlen(helpstr))/2 + 1,
2156            screen->Size().y-wm->font()->height()-5 + 1, helpstr, wm->dark_color());
2157        wm->font()->put_string(screen, screen->Size().x/2-(wm->font()->width()*strlen(helpstr))/2,
2158            screen->Size().y-wm->font()->height()-5, helpstr, wm->bright_color());
2159    }
2160/*    else
2161    {
2162        char *helpstr="PRESS h FOR HELP";
2163        wm->font()->put_string(screen, screen->Size().x-wm->font()->width()*strlen(helpstr)-5,
2164            screen->Size().y-wm->font()->height()-5, helpstr);
2165    }*/
2166/*    int dc = cache.img(window_colors)->pixel(0, 2);
2167    int mc = cache.img(window_colors)->pixel(1, 2);
2168    int bc = cache.img(window_colors)->pixel(2, 2);
2169    screen->line(0, 0, screen->Size().x-1, 0, dc);
2170    screen->line(0, 0, 0, screen->Size().y-1, dc);
2171    screen->line(0, screen->Size().y-1, screen->Size().x-1, screen->Size().y-1, bc);
2172    screen->line(screen->Size().x-1, 0, screen->Size().x-1, screen->Size().y-1, bc); */
2173
2174    for(view *f = first_view; f; f = f->next)
2175        draw_map(f, 0);
2176
2177    sbar.redraw(screen);
2178}
2179
2180int external_print = 0;
2181
2182void start_sound(int argc, char **argv)
2183{
2184  sfx_volume = music_volume = 127;
2185
2186  for(int i = 1; i < argc; i++)
2187    if(!strcmp(argv[i], "-sfx_volume"))
2188    {
2189      i++;
2190      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2191        sfx_volume = atoi(argv[i]);
2192      else printf("Bad sound effects volume level, use 0..127\n");
2193    }
2194    else if(!strcmp(argv[i], "-music_volume"))
2195    {
2196      i++;
2197      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2198        music_volume = atoi(argv[i]);
2199      else printf("Bad music volume level, use 0..127\n");
2200    }
2201
2202  sound_avail = sound_init(argc, argv);
2203}
2204
2205void game_printer(char *st)
2206{
2207  if(dev_console && !external_print)
2208  {
2209    dev_console->put_string(st);
2210  }
2211  else fprintf(stderr, "%s", st);
2212}
2213
2214
2215void game_getter(char *st, int max)
2216{
2217  if(!max) return;
2218  max--;
2219  *st = 0;
2220  if(dev_console && !external_print)
2221  {
2222    dev_console->show();
2223    int t = 0;
2224    event ev;
2225    do
2226    {
2227      get_event(ev);
2228      if(ev.type == EV_KEY)
2229      {
2230    if(ev.key == JK_BACKSPACE)
2231    {
2232      if(t)
2233      {
2234        dev_console->print_f("%c", ev.key);
2235        t--;
2236        st--;
2237        *st = 0;
2238        max++;
2239      }
2240    } else if(ev.key>=' ' && ev.key<='~')
2241    {
2242      dev_console->print_f("%c", ev.key);
2243      *st = ev.key;
2244      t++;
2245      max--;
2246      st++;
2247      *st = 0;
2248    }
2249      }
2250      wm->flush_screen();
2251    } while(ev.type != EV_KEY || ev.key != JK_ENTER);
2252    dprintf("\n");
2253  }
2254  else
2255  {
2256    if(fgets(st, max, stdin))
2257    {
2258      if(*st)
2259        st[strlen(st)-1]=0;
2260    }
2261  }
2262}
2263
2264
2265void show_startup()
2266{
2267    dprintf("Abuse version %s\n", PACKAGE_VERSION);
2268}
2269
2270char *get_line(int open_braces)
2271{
2272  char *line=(char *)malloc(1000);
2273  fgets(line, 1000, stdin);
2274
2275  char prev=' ';
2276  for(char *s = line; *s && (prev!=' ' || *s!=';'); s++)
2277  {
2278    prev=*s;
2279    if(*s=='(') open_braces++;
2280    else if(*s==')') open_braces--;
2281  }
2282  if(open_braces < 0)
2283    fprintf(stderr, "\nToo many)'s\n");
2284  else if(open_braces > 0)
2285  {
2286    char *s2 = get_line(open_braces);
2287    line=(char *)realloc(line, strlen(line)+strlen(s2)+1);
2288    strcat(line, s2);
2289    free(s2);
2290  }
2291  return line;
2292}
2293
2294void check_for_lisp(int argc, char **argv)
2295{
2296    for(int i = 1; i < argc; i++)
2297    {
2298        if(!strcmp(argv[i], "-lisp"))
2299        {
2300            lisp_init();
2301            char const *eof_char = "Ctrl-D";
2302            fprintf(stderr,
2303                    " CLIVE (C) 1995 Jonathan Clark, all rights reserved\n"
2304                    "   (C LISP interpreter and various extentions)\n"
2305                    "Type (%s) to exit\n", eof_char);
2306
2307            while(!feof(stdin))
2308            {
2309                fprintf(stderr, "Lisp> ");
2310                char *l = get_line(0);
2311                char const *s = l;
2312                while(*s)
2313                {
2314                    LObject *prog = LObject::Compile(s);
2315                    l_user_stack.push(prog);
2316                    while(*s==' ' || *s=='\t' || *s=='\r' || *s=='\n') s++;
2317                    prog->Eval()->Print();
2318                    l_user_stack.pop(1);
2319                }
2320                free(l);
2321            }
2322            fprintf(stderr, "End of input : bye\n");
2323            exit(0);
2324        }
2325    }
2326}
2327
2328
2329void music_check()
2330{
2331  if(sound_avail & MUSIC_INITIALIZED)
2332  {
2333    if(current_song && !current_song->playing())
2334    {
2335      current_song->play(music_volume);
2336      dprintf("song finished\n");
2337    }
2338    if(!current_song)
2339    {
2340
2341      current_song = new song("music/intro.hmi");
2342      current_song->play(music_volume);
2343
2344/*      if(DEFINEDP(symbol_function(l_next_song)))  // if user function installed, call it to load up next song
2345      {
2346    int sp = current_space;
2347    current_space = PERM_SPACE;
2348    ((LSymbol *)l_next_song)->EvalFunction(NULL);
2349    current_space = sp;
2350      } */
2351    }
2352  }
2353}
2354
2355void setup(int argc, char **argv);
2356
2357void share_end();
2358void show_end();
2359
2360void show_sell(int abortable);
2361
2362extern pmenu *dev_menu;
2363
2364void game_net_init(int argc, char **argv)
2365{
2366#if !defined __CELLOS_LV2__
2367  int nonet=!net_init(argc, argv);
2368  if(nonet)
2369    dprintf("No network driver, or network driver returned failure\n");
2370  else
2371  {
2372    set_file_opener(open_nfs_file);
2373    if(main_net_cfg && main_net_cfg->state == net_configuration::CLIENT)
2374    {
2375      if(set_file_server(net_server))
2376      start_running = 1;
2377      else
2378      {
2379                dprintf("Unable to attach to server, quitting\n");
2380                exit(0);
2381      }
2382    } else
2383    {
2384      int i;
2385      for(i = 1; i < argc - 1; i++)
2386      if(!strcmp(argv[i], "-fs"))
2387      if(!set_file_server(argv[i + 1]))
2388      dprintf("could not set default file server to %s\n", argv[i + 1]);
2389    }
2390  }
2391#endif
2392}
2393
2394int main(int argc, char *argv[])
2395{
2396    start_argc = argc;
2397    start_argv = argv;
2398
2399    for (int i = 0; i < argc; i++)
2400    {
2401        if (!strcmp(argv[i], "-cprint"))
2402            external_print = 1;
2403    }
2404
2405#if (defined(__APPLE__) && !defined(__MACH__))
2406    unsigned char km[16];
2407
2408    fprintf(stderr, "Mac Options: ");
2409    xres = 320; yres = 200;
2410    GetKeys((uint32_t*)&km);
2411    if ((km[ 0x3a >>3] >> (0x3a & 7)) &1 != 0)
2412    {
2413        dev|=EDIT_MODE;
2414        start_edit = 1;
2415        start_running = 1;
2416        disable_autolight = 1;
2417        fprintf(stderr, "Edit Mode...");
2418    }
2419    if ((km[ 0x3b >>3] >> (0x3b & 7)) &1 != 0)
2420    {
2421        PixMult = 1;
2422        fprintf(stderr, "Single Pixel...");
2423    }
2424    else
2425    {
2426        PixMult = 2;
2427        fprintf(stderr, "Double Pixel...");
2428    }
2429    if ((km[ 0x38 >>3] >> (0x38 & 7)) &1 != 0)
2430    {
2431        xres *= 2;  yres *= 2;
2432        fprintf(stderr, "Double Size...");
2433    }
2434    fprintf(stderr, "\n");
2435
2436    if (tcpip.installed())
2437        fprintf(stderr, "Using %s\n", tcpip.name());
2438#endif
2439
2440    set_dprinter(game_printer);
2441    set_dgetter(game_getter);
2442    set_no_space_handler(handle_no_space);
2443
2444    setup(argc, argv);
2445
2446    show_startup();
2447
2448    start_sound(argc, argv);
2449
2450    stat_man = new text_status_manager();
2451    if (!get_option("-no_timer"))
2452        timer_init();
2453
2454#if !defined __CELLOS_LV2__
2455    // look to see if we are supposed to fetch the data elsewhere
2456    if (getenv("ABUSE_PATH"))
2457        set_filename_prefix(getenv("ABUSE_PATH"));
2458
2459    // look to see if we are supposed to save the data elsewhere
2460    if (getenv("ABUSE_SAVE_PATH"))
2461        set_save_filename_prefix(getenv("ABUSE_SAVE_PATH"));
2462#endif
2463
2464    jrand_init();
2465    jrand(); // so compiler doesn't complain
2466
2467    set_spec_main_file("abuse.spe");
2468    check_for_lisp(argc, argv);
2469
2470    do
2471    {
2472        if (main_net_cfg && !main_net_cfg->notify_reset())
2473        {
2474            if (!get_option("-no_timer"))
2475                timer_uninit();
2476            sound_uninit();
2477            exit(0);
2478        }
2479
2480        game_net_init(argc, argv);
2481        lisp_init();
2482
2483        dev_init(argc, argv);
2484
2485        Game *g = new Game(argc, argv);
2486
2487        dev_cont = new dev_controll();
2488        dev_cont->load_stuff();
2489
2490        g->get_input(); // prime the net
2491
2492#if !defined __CELLOS_LV2__
2493        for (int i = 1; i + 1 < argc; i++)
2494        {
2495            if (!strcmp(argv[i], "-server"))
2496            {
2497                if (!become_server(argv[i + 1]))
2498                {
2499                    dprintf("unable to become a server\n");
2500                    exit(0);
2501                }
2502                break;
2503            }
2504        }
2505
2506        if (main_net_cfg)
2507            wait_min_players();
2508
2509        net_send(1);
2510        if (net_start())
2511        {
2512            g->step(); // process all the objects in the world
2513            g->calc_speed();
2514            g->update_screen(); // redraw the screen with any changes
2515        }
2516#endif
2517
2518        while (!g->done())
2519        {
2520            music_check();
2521
2522            if (req_end)
2523            {
2524                delete current_level; current_level = NULL;
2525
2526                show_end();
2527
2528                the_game->set_state(MENU_STATE);
2529                req_end = 0;
2530            }
2531
2532            if (demo_man.current_state() == demo_manager::NORMAL)
2533                net_receive();
2534
2535            // see if a request for a level load was made during the last tick
2536            if (req_name[0])
2537            {
2538                g->load_level(req_name);
2539                req_name[0] = 0;
2540                g->draw(g->state == SCENE_STATE);
2541            }
2542
2543            //if (demo_man.current_state() != demo_manager::PLAYING)
2544                g->get_input();
2545
2546            if (demo_man.current_state() == demo_manager::NORMAL)
2547                net_send();
2548            else
2549                demo_man.do_inputs();
2550
2551#if !defined __CELLOS_LV2__
2552            service_net_request();
2553#endif
2554
2555            // process all the objects in the world
2556            g->step();
2557#if !defined __CELLOS_LV2__
2558            server_check();
2559#endif
2560            g->calc_speed();
2561
2562            // see if a request for a level load was made during the last tick
2563            if (!req_name[0])
2564                g->update_screen(); // redraw the screen with any changes
2565        }
2566
2567#if !defined __CELLOS_LV2__
2568        net_uninit();
2569
2570        if (net_crcs)
2571            net_crcs->clean_up();
2572        delete net_crcs; net_crcs = NULL;
2573#endif
2574
2575        delete chat;
2576
2577        milli_wait(500);
2578
2579        delete small_render; small_render = NULL;
2580
2581        if (current_song)
2582            current_song->stop();
2583        delete current_song; current_song = NULL;
2584
2585        cache.empty();
2586
2587        delete dev_console; dev_console = NULL;
2588        delete dev_menu; dev_menu = NULL;
2589        delete g; g = NULL;
2590        delete old_pal; old_pal = NULL;
2591
2592        compiled_uninit();
2593        delete_all_lights();
2594        free(white_light_initial);
2595
2596        for (int i = 0; i < TTINTS; i++)
2597            free(tints[i]);
2598
2599        dev_cleanup();
2600        delete dev_cont; dev_cont = NULL;
2601        delete stat_man; stat_man = new text_status_manager();
2602
2603        if (!(main_net_cfg && main_net_cfg->restart_state()))
2604        {
2605            LSymbol *end_msg = LSymbol::FindOrCreate("end_msg");
2606            if (DEFINEDP(end_msg->GetValue()))
2607                printf("%s\n", lstring_value(end_msg->GetValue()));
2608        }
2609
2610        lisp_uninit();
2611
2612#if !defined __CELLOS_LV2__
2613        base->packet.packet_reset();
2614#endif
2615    }
2616    while (main_net_cfg && main_net_cfg->restart_state());
2617
2618    delete stat_man;
2619    delete main_net_cfg; main_net_cfg = NULL;
2620
2621    set_filename_prefix(NULL);  // dealloc this mem if there was any
2622    set_save_filename_prefix(NULL);
2623
2624    if (!get_option("-no_timer"))
2625        timer_uninit();
2626
2627    sound_uninit();
2628
2629    return 0;
2630}
2631
Note: See TracBrowser for help on using the repository browser.