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

Last change on this file since 577 was 577, checked in by Sam Hocevar, 12 years ago

game: get rid of milli_wait() and rewrite the fixed framerate handling.

File size: 66.6 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    Timer tmp; tmp.WaitMs(400);
1247    fade_out(32);
1248
1249    void *space_snd = LSymbol::FindOrCreate("SPACE_SND")->GetValue();
1250    char *str = lstring_value(LSymbol::FindOrCreate("plot_start")->Eval());
1251
1252    bFILE *fp = open_file("art/smoke.spe", "rb");
1253    if(!fp->open_failure())
1254    {
1255        spec_directory sd(fp);
1256        palette *old_pal = pal;
1257        pal = new palette(sd.find(SPEC_PALETTE), fp);
1258        pal->shift(1);
1259
1260        image *gray = new image(fp, sd.find("gray_pict"));
1261        image *smoke[5];
1262
1263        char nm[20];
1264        for (int i = 0; i < 5; i++)
1265        {
1266            sprintf(nm, "smoke%04d.pcx", i + 1);
1267            smoke[i] = new image(fp, sd.find(nm));
1268        }
1269
1270        screen->clear();
1271        pal->load();
1272
1273        int dx = (xres + 1) / 2 - gray->Size().x / 2, dy = (yres + 1) / 2 - gray->Size().y / 2;
1274        gray->put_image(screen, dx, dy);
1275        smoke[0]->put_image(screen, dx + 24, dy + 5);
1276
1277        fade_in(NULL, 16);
1278        uint8_t cmap[32];
1279        for(int i = 0; i < 32; i++)
1280        cmap[i] = pal->find_closest(i * 256 / 32, i * 256 / 32, i * 256 / 32);
1281
1282        event ev;
1283        ev.type = EV_SPURIOUS;
1284        Timer total;
1285
1286        while (ev.type != EV_KEY && ev.type != EV_MOUSE_BUTTON)
1287        {
1288            Timer frame;
1289
1290            // 100 ms per step
1291            int i = (int)(total.PollMs() / 100.f);
1292            if (i >= 320)
1293                break;
1294
1295            gray->put_image(screen, dx, dy);
1296            smoke[i % 5]->put_image(screen, dx + 24, dy + 5);
1297            text_draw(205 - i, dx + 15, dy, dx + 320 - 15, dy + 199, str, wm->font(), cmap, wm->bright_color());
1298            wm->flush_screen();
1299            time_marker now;
1300
1301            while(wm->event_waiting() && ev.type != EV_KEY)
1302                wm->get_event(ev);
1303
1304            if((i % 5) == 0 && DEFINEDP(space_snd) && (sound_avail & SFX_INITIALIZED))
1305                cache.sfx(lnumber_value(space_snd))->play(sfx_volume * 90 / 127);
1306
1307            frame.WaitMs(25.f);
1308        }
1309
1310        the_game->reset_keymap();
1311
1312        fade_out(16);
1313
1314        for (int i = 0; i < 5; i++)
1315            delete smoke[i];
1316        delete gray;
1317        delete pal;
1318        pal = old_pal;
1319    }
1320    delete fp;
1321
1322    if(title_screen >= 0)
1323        fade_in(cache.img(title_screen), 32);
1324}
1325
1326extern int start_edit;
1327
1328void Game::request_end()
1329{
1330  req_end = 1;
1331}
1332
1333Game::Game(int argc, char **argv)
1334{
1335  int i;
1336  req_name[0]=0;
1337  bg_xmul = bg_ymul = 1;
1338  bg_xdiv = bg_ydiv = 8;
1339  last_input = NULL;
1340  current_automap = NULL;
1341  current_level = NULL;
1342  refresh = 1;
1343  the_game = this;
1344  top_menu = joy_win = NULL;
1345  old_view = first_view = NULL;
1346  nplayers = 1;
1347
1348  help_text_frames = 0;
1349  strcpy(help_text, "");
1350
1351
1352  for(i = 1; i < argc; i++)
1353    if(!strcmp(argv[i], "-no_delay"))
1354    {
1355      no_delay = 1;
1356      dprintf("Frame delay off (-nodelay)\n");
1357    }
1358
1359
1360  image_init();
1361  zoom = 15;
1362  no_delay = 0;
1363
1364  if(get_option("-use_joy"))
1365  {
1366    has_joystick = joy_init(argc, argv);
1367    dprintf("Joystick : ");
1368    if(has_joystick) dprintf("detected\n");
1369    else dprintf("not detected\n");
1370  }
1371  else has_joystick = 0;
1372
1373    // Clean up that old crap
1374    char *fastpath = (char *)malloc(strlen(get_save_filename_prefix()) + 13);
1375    sprintf(fastpath, "%sfastload.dat", get_save_filename_prefix());
1376    unlink(fastpath);
1377    free(fastpath);
1378
1379//    ProfilerInit(collectDetailed, bestTimeBase, 2000, 200); //prof
1380    load_data(argc, argv);
1381//    ProfilerDump("\pabuse.prof");  //prof
1382//    ProfilerTerm();
1383
1384  get_key_bindings();
1385
1386  reset_keymap();                   // we think all the keys are up right now
1387  finished = false;
1388
1389  calc_light_table(pal);
1390
1391#if !defined __CELLOS_LV2__
1392  if(current_level == NULL && net_start())  // if we joined a net game get level from server
1393  {
1394    if(!request_server_entry())
1395    {
1396      exit(0);
1397    }
1398    net_reload();
1399//    load_level(NET_STARTFILE);
1400  }
1401#endif
1402
1403  set_mode(19, argc, argv);
1404  if(get_option("-2") && (xres < 639 || yres < 399))
1405  {
1406    close_graphics();
1407    fprintf(stderr, "Resolution must be > 640x400 to use -2 option\n");
1408    exit(0);
1409  }
1410  pal->load();
1411
1412  recalc_local_view_space();   // now that we know what size the screen is...
1413
1414  dark_color = get_color(cache.img(window_colors)->Pixel(vec2i(2, 0)));
1415  bright_color = get_color(cache.img(window_colors)->Pixel(vec2i(0, 0)));
1416  med_color = get_color(cache.img(window_colors)->Pixel(vec2i(1, 0)));
1417
1418  morph_dark_color = get_color(cache.img(window_colors)->Pixel(vec2i(2, 1)));
1419  morph_bright_color = get_color(cache.img(window_colors)->Pixel(vec2i(0, 1)));
1420  morph_med_color = get_color(cache.img(window_colors)->Pixel(vec2i(1, 1)));
1421  morph_sel_frame_color = pal->find_closest(255, 255, 0);
1422  light_connection_color = morph_sel_frame_color;
1423
1424  if(NILP(symbol_value(l_default_font)))
1425  {
1426    printf("No font defined, set symbol default-font to an image name\n");
1427    exit(0);
1428  }
1429  int font_pict;
1430  if(big_font_pict != -1)
1431  {
1432    if(small_font_pict != -1)
1433    {
1434      if(xres/(start_doubled ? 2 : 1)>400)
1435      {
1436    font_pict = big_font_pict;
1437      }
1438      else font_pict = small_font_pict;
1439    } else font_pict = big_font_pict;
1440  } else font_pict = small_font_pict;
1441
1442  if(console_font_pict == -1) console_font_pict = font_pict;
1443  game_font = new JCFont(cache.img(font_pict));
1444
1445  console_font = new JCFont(cache.img(console_font_pict));
1446
1447  wm = new WindowManager(screen, pal, bright_color,
1448                         med_color, dark_color, game_font);
1449
1450  delete stat_man;  // move to a graphical status manager
1451  gui_status_manager *gstat = new gui_status_manager();
1452  gstat->set_window_title("status");
1453  stat_man = gstat;
1454
1455
1456  chat = new chat_console( console_font, 50, 6);
1457
1458  if(!wm->has_mouse())
1459  {
1460    close_graphics();
1461    image_uninit();
1462    printf("No mouse driver detected, please rectify.\n");
1463    exit(0);
1464  }
1465
1466
1467  gamma_correct(pal);
1468
1469#if defined __CELLOS_LV2__
1470  if(!start_edit)
1471    do_title();
1472#else
1473  if(main_net_cfg == NULL || (main_net_cfg->state != net_configuration::SERVER &&
1474                 main_net_cfg->state != net_configuration::CLIENT))
1475  {
1476    if(!start_edit && !net_start())
1477      do_title();
1478  } else if(main_net_cfg && main_net_cfg->state == net_configuration::SERVER)
1479  {
1480    the_game->load_level(level_file);
1481    start_running = 1;
1482  }
1483#endif
1484
1485
1486  dev|= DRAW_FG_LAYER | DRAW_BG_LAYER | DRAW_PEOPLE_LAYER | DRAW_HELP_LAYER | DRAW_LIGHTS | DRAW_LINKS;
1487
1488  if(dev & EDIT_MODE)
1489    set_frame_size(0);
1490//  do_intro();
1491  state = START_STATE;         // first set the state to one that has windows
1492
1493
1494  if(start_running)
1495    set_state(RUN_STATE);
1496  else
1497  {
1498    screen->clear();
1499    if(title_screen >= 0)
1500    {
1501      image *tit = cache.img(title_screen);
1502      tit->put_image(screen, screen->Size().x/2 - tit->Size().x/2,
1503                    screen->Size().y/2 - tit->Size().y/2);
1504    }
1505    set_state(MENU_STATE);   // then go to menu state so windows will turn off
1506  }
1507}
1508
1509time_marker *led_last_time = NULL;
1510static float avg_fps = 15.0f, possible_fps = 15.0f;
1511
1512void Game::toggle_delay()
1513{
1514    no_delay = !no_delay;
1515    show_help(symbol_str(no_delay ? "delay_off" : "delay_on"));
1516    avg_fps = possible_fps = 15.0f;
1517}
1518
1519void Game::show_time()
1520{
1521    if (!first_view || !fps_on)
1522        return;
1523
1524    char str[16];
1525    sprintf(str, "%ld", (long)(avg_fps * 10.0));
1526    console_font->put_string(screen, first_view->cx1, first_view->cy1, str);
1527
1528    sprintf(str, "%d", total_active);
1529    console_font->put_string(screen, first_view->cx1, first_view->cy1 + 10, str);
1530}
1531
1532void Game::update_screen()
1533{
1534  if(state == HELP_STATE)
1535    draw_help();
1536  else if(current_level)
1537  {
1538    if(!(dev & EDIT_MODE) || refresh)
1539    {
1540      view *f = first_view;
1541      current_level->clear_active_list();
1542      for(; f; f = f->next)
1543      {
1544    if(f->focus)
1545    {
1546      int w, h;
1547
1548      w=(f->cx2 - f->cx1 + 1);
1549      h=(f->cy2 - f->cy1 + 1);
1550
1551      total_active += current_level->add_drawables(f->xoff()-w / 4, f->yoff()-h / 4,
1552                             f->xoff()+w + w / 4, f->yoff()+h + h / 4);
1553
1554    }
1555      }
1556
1557      for(f = first_view; f; f = f->next)
1558      {
1559        if(f->drawable())
1560    {
1561      if(interpolate_draw)
1562      {
1563            draw_map(f, 1);
1564        wm->flush_screen();
1565      }
1566          draw_map(f, 0);
1567    }
1568      }
1569      if(current_automap)
1570      current_automap->draw();
1571    }
1572    if(state == PAUSE_STATE)
1573    {
1574      for(view *f = first_view; f; f = f->next)
1575        cache.img(pause_image)->put_image(screen, (f->cx1 + f->cx2)/2 - cache.img(pause_image)->Size().x/2,
1576                   f->cy1 + 5, 1);
1577    }
1578
1579    show_time();
1580  }
1581
1582  if(state == RUN_STATE && cache.prof_is_on())
1583    cache.prof_poll_end();
1584
1585  wm->flush_screen();
1586
1587}
1588
1589void Game::do_intro()
1590{
1591
1592}
1593
1594// FIXME: refactor this to use the Lol Engine main fixed-framerate loop?
1595int Game::calc_speed()
1596{
1597    static Timer frame_timer;
1598    static int first = 1;
1599
1600    if (first)
1601    {
1602        first = 0;
1603        return 0;
1604    }
1605
1606    // Find average fps for last 10 frames
1607    float fps = 1000.0f / Max(1.0f, frame_timer.PollMs());
1608
1609    avg_fps = 0.9f * avg_fps + 0.1f * fps;
1610    possible_fps = 0.9f * possible_fps + 0.1f * fps;
1611
1612    if (avg_fps > 14)
1613        massive_frame_panic = Max(0, Min(20, massive_frame_panic - 1));
1614
1615    int ret = 0;
1616
1617    if (dev & EDIT_MODE)
1618    {
1619        // ECS - Added this case and the wait.  It's a cheap hack to ensure
1620        // that we don't exceed 30FPS in edit mode and hog the CPU.
1621        frame_timer.WaitMs(33);
1622    }
1623    else if (avg_fps > 15 && need_delay)
1624    {
1625        frame_panic = 0;
1626        if (!no_delay)
1627        {
1628            frame_timer.WaitMs(1000.0f / 15);
1629            avg_fps -= 0.1f * fps;
1630            avg_fps += 0.1f * 15.0f;
1631        }
1632    }
1633    else if (avg_fps < 14)
1634    {
1635        if(avg_fps < 10)
1636            massive_frame_panic++;
1637        frame_panic++;
1638        // All is lost, don't sleep during this frame
1639        ret = 1;
1640    }
1641
1642    // Ignore our wait time, we're more interested in the frame time
1643    frame_timer.GetMs();
1644    return ret;
1645}
1646
1647extern int start_edit;
1648
1649void Game::get_input()
1650{
1651    event ev;
1652    idle_ticks++;
1653    while(event_waiting())
1654    {
1655        get_event(ev);
1656
1657        if(ev.type == EV_MOUSE_MOVE)
1658        {
1659            last_input = ev.window;
1660        }
1661        // don't process repeated keys in the main window, it will slow down the game to handle such
1662        // useless events. However in other windows it might be useful, such as in input windows
1663        // where you want to repeatedly scroll down...
1664        if(ev.type != EV_KEY || !key_down(ev.key) || ev.window || (dev & EDIT_MODE))
1665        {
1666#if !defined __CELLOS_LV2__
1667            if(ev.type == EV_KEY)
1668            {
1669                set_key_down(ev.key, 1);
1670                if(playing_state(state))
1671                {
1672                    if(ev.key < 256)
1673                    {
1674                        if(chat && chat->chat_event(ev))
1675                            base->packet.write_uint8(SCMD_CHAT_KEYPRESS);
1676                        else
1677                            base->packet.write_uint8(SCMD_KEYPRESS);
1678                    }
1679                    else
1680                        base->packet.write_uint8(SCMD_EXT_KEYPRESS);
1681                    base->packet.write_uint8(client_number());
1682                    if(ev.key > 256)
1683                        base->packet.write_uint8(ev.key - 256);
1684                    else
1685                        base->packet.write_uint8(ev.key);
1686                }
1687            }
1688            else if(ev.type == EV_KEYRELEASE)
1689            {
1690                set_key_down(ev.key, 0);
1691                if(playing_state(state))
1692                {
1693                    if(ev.key < 256)
1694                        base->packet.write_uint8(SCMD_KEYRELEASE);
1695                    else
1696                        base->packet.write_uint8(SCMD_EXT_KEYRELEASE);
1697                    base->packet.write_uint8(client_number());
1698                    if(ev.key > 255)
1699                        base->packet.write_uint8(ev.key - 256);
1700                    else
1701                        base->packet.write_uint8(ev.key);
1702                }
1703            }
1704#endif
1705
1706            if((dev & EDIT_MODE) || start_edit || ev.type == EV_MESSAGE)
1707            {
1708                dev_cont->handle_event(ev);
1709            }
1710
1711            view *v = first_view;
1712            for(; v; v = v->next)
1713            {
1714                if(v->local_player() && v->handle_event(ev))
1715                    ev.type = EV_SPURIOUS;       // if the event was used by the view, gobble it up
1716            }
1717
1718            if(current_automap)
1719            {
1720                current_automap->handle_event(ev);
1721            }
1722
1723            help_handle_event(ev);
1724            mousex = last_demo_mx;
1725            mousey = last_demo_my;
1726
1727            if(ev.type == EV_MESSAGE)
1728            {
1729                switch (ev.message.id)
1730                {
1731                    case CALB_JOY:
1732                    {
1733                        if(!joy_win)
1734                        {
1735                            joy_win = wm->new_window(80, 50, -1, -1,
1736                                    new button(70, 9, JOY_OK, "OK",
1737                                    new info_field(0, 30, DEV_NULL,
1738                                    " Center joystick and\n"
1739                                    "press the fire button", NULL)),
1740                                    "Joystick");
1741                            set_state(JOY_CALB_STATE);
1742                        }
1743                    }
1744                    case TOP_MENU:
1745                    {
1746                        menu_select(ev);
1747                    } break;
1748                    case DEV_QUIT:
1749                    {
1750                        finished = true;
1751                    } break;
1752                }
1753            }
1754            else if(ev.type == EV_CLOSE_WINDOW && ev.window == top_menu)
1755            {
1756                wm->close_window(top_menu);
1757                top_menu = NULL;
1758            }
1759
1760            switch(state)
1761            {
1762                case JOY_CALB_STATE:
1763                {
1764                    joy_calb(ev);
1765                } break;
1766                case INTRO_START_STATE:
1767                {
1768                    do_intro();
1769                    if(dev & EDIT_MODE)
1770                        set_state(RUN_STATE);
1771                    else
1772                        set_state(MENU_STATE);
1773                } break;
1774                case PAUSE_STATE:
1775                {
1776                    if(ev.type == EV_KEY && (ev.key == JK_SPACE || ev.key == JK_ENTER))
1777                    {
1778                        set_state(RUN_STATE);
1779                    }
1780                } break;
1781                case RUN_STATE:
1782                {
1783                    if(ev.window == NULL)
1784                    {
1785                        switch (ev.type)
1786                        {
1787                            case EV_KEY:
1788                            {
1789                                switch (ev.key)
1790                                {
1791                                    case 'm':
1792                                    {
1793                                        if(dev & MAP_MODE)
1794                                            dev -= MAP_MODE;
1795                                        else if((player_list && player_list->next) || dev & EDIT_MODE)
1796                                            dev |= MAP_MODE;
1797
1798                                        if(!(dev & MAP_MODE))
1799                                        {
1800                                            if(dev_cont->tbw)
1801                                                dev_cont->toggle_toolbar();
1802                                            edit_mode = ID_DMODE_DRAW;
1803                                        }
1804                                        need_refresh();
1805                                    } break;
1806                                    case 'v':
1807                                    {
1808                                        wm->push_event(new event(DO_VOLUME, NULL));
1809                                    } break;
1810                                    case 'p':
1811                                    {
1812                                        if(!(dev & EDIT_MODE) && (!main_net_cfg ||
1813                                            (main_net_cfg->state != net_configuration::SERVER &&
1814                                            main_net_cfg->state != net_configuration::CLIENT)))
1815                                        {
1816                                            set_state(PAUSE_STATE);
1817                                        }
1818                                    } break;
1819                                    case 'S':
1820                                    {
1821                                        if(start_edit)
1822                                        {
1823                                            wm->push_event(new event(ID_LEVEL_SAVE, NULL));
1824                                        }
1825                                    } break;
1826                                    case JK_TAB:
1827                                        if(start_edit)
1828                                            toggle_edit_mode();
1829                                        need_refresh();
1830                                        break;
1831                                    case 'c':
1832                                    case 'C':
1833                                        if(chatting_enabled && (!(dev & EDIT_MODE) && chat))
1834                                            chat->toggle();
1835                                        break;
1836                                    case '9':
1837                                        dev = dev ^ PERFORMANCE_TEST_MODE;
1838                                        need_refresh();
1839                                        break;
1840                                }
1841                            } break;
1842                            case EV_RESIZE:
1843                            {
1844                                view *v;
1845                                for(v = first_view; v; v = v->next)  // see if any views need to change size
1846                                {
1847                                    if(v->local_player())
1848                                    {
1849                                        int w = (xres - 10)/(small_render ? 2 : 1);
1850                                        int h = (yres - 10)/(small_render ? 2 : 1);
1851
1852                                        v->suggest.send_view = 1;
1853                                        v->suggest.cx1 = 5;
1854                                        v->suggest.cx2 = 5 + w;
1855                                        v->suggest.cy1 = 5;
1856                                        v->suggest.cy2 = 5 + h;
1857                                        v->suggest.pan_x = v->pan_x;
1858                                        v->suggest.pan_y = v->pan_y;
1859                                        v->suggest.shift_down = v->shift_down;
1860                                        v->suggest.shift_right = v->shift_right;
1861                                    }
1862                                }
1863                                draw();
1864                            } break;
1865                            case EV_REDRAW:
1866                            {
1867                                screen->AddDirty(ev.redraw.x1, ev.redraw.y1,
1868                                    ev.redraw.x2 + 1, ev.redraw.y2 + 1);
1869                            } break;
1870                            case EV_MESSAGE:
1871                            {
1872                                switch (ev.message.id)
1873                                {
1874                                    case RAISE_SFX:
1875                                    case LOWER_SFX:
1876                                    case RAISE_MUSIC:
1877                                    case LOWER_MUSIC:
1878                                    {
1879                                        if(ev.message.id == RAISE_SFX && sfx_volume != 127)
1880                                            sfx_volume = Min(127, sfx_volume + 16);
1881                                        if(ev.message.id == LOWER_SFX && sfx_volume != 0)
1882                                            sfx_volume = Max(sfx_volume - 16, 0);
1883                                        if(ev.message.id == RAISE_MUSIC && music_volume != 126)
1884                                        {
1885                                            music_volume = Min(music_volume + 16, 127);
1886                                            if(current_song && (sound_avail & MUSIC_INITIALIZED))
1887                                                current_song->set_volume(music_volume);
1888                                        }
1889
1890                                        if(ev.message.id == LOWER_MUSIC && music_volume != 0)
1891                                        {
1892                                            music_volume = Max(music_volume - 16, 0);
1893                                            if(current_song && (sound_avail & MUSIC_INITIALIZED))
1894                                                current_song->set_volume(music_volume);
1895                                        }
1896
1897                                        ((button *)ev.message.data)->push();
1898/*                                        volume_window->inm->redraw();
1899                                        draw_value(volume_window->screen, 2, 43,
1900                                                (volume_window->x2()-volume_window->x1()-1), 8, sfx_volume, 127);
1901                                        draw_value(volume_window->screen, 2, 94,
1902                                                (volume_window->x2()-volume_window->x1()-1), 8, music_volume, 127);
1903*/
1904                                        break;
1905                                    }
1906                                }
1907                            }
1908                        }
1909                    }
1910                } break;
1911            }
1912        }
1913    }
1914}
1915
1916
1917void net_send(int force = 0)
1918{
1919#if !defined __CELLOS_LV2__
1920  if((!(dev & EDIT_MODE)) || force)
1921  {
1922    if(demo_man.state == demo_manager::PLAYING)
1923    {
1924      base->input_state = INPUT_PROCESSING;
1925    } else
1926    {
1927
1928
1929
1930      if(!player_list->focus)
1931      {
1932    dprintf("Players have not been created\ncall create_players");
1933    exit(0);
1934      }
1935
1936
1937      view *p = player_list;
1938      for(; p; p = p->next)
1939        if(p->local_player())
1940      p->get_input();
1941
1942
1943      base->packet.write_uint8(SCMD_SYNC);
1944      base->packet.write_uint16(make_sync());
1945
1946      if(base->join_list)
1947      base->packet.write_uint8(SCMD_RELOAD);
1948
1949      //      printf("save tick %d, pk size=%d, rand_on=%d, sync=%d\n", current_level->tick_counter(),
1950      //         base->packet.packet_size(), rand_on, make_sync());
1951      send_local_request();
1952    }
1953  }
1954#endif
1955}
1956
1957void net_receive()
1958{
1959#if !defined __CELLOS_LV2__
1960  if(!(dev & EDIT_MODE) && current_level)
1961  {
1962    uint8_t buf[PACKET_MAX_SIZE + 1];
1963    int size;
1964
1965    if(demo_man.state == demo_manager::PLAYING)
1966    {
1967      if(!demo_man.get_packet(buf, size))
1968        size = 0;
1969      base->packet.packet_reset();
1970      base->mem_lock = 0;
1971    } else
1972    {
1973      size = get_inputs_from_server(buf);
1974      if(demo_man.state == demo_manager::RECORDING)
1975    demo_man.save_packet(buf, size);
1976    }
1977
1978    process_packet_commands(buf, size);
1979  }
1980#endif
1981}
1982
1983void Game::step()
1984{
1985  clear_tmp();
1986  if(current_level)
1987  {
1988    current_level->unactivate_all();
1989    total_active = 0;
1990    for(view *f = first_view; f; f = f->next)
1991    {
1992      if(f->focus)
1993      {
1994    f->update_scroll();
1995    int w, h;
1996
1997    w=(f->cx2 - f->cx1 + 1);
1998    h=(f->cy2 - f->cy1 + 1);
1999        total_active += current_level->add_actives(f->xoff()-w / 4, f->yoff()-h / 4,
2000                         f->xoff()+w + w / 4, f->yoff()+h + h / 4);
2001      }
2002    }
2003  }
2004
2005  if(state == RUN_STATE)
2006  {
2007    if((dev & EDIT_MODE) || (main_net_cfg && (main_net_cfg->state == net_configuration::CLIENT ||
2008                         main_net_cfg->state == net_configuration::SERVER)))
2009      idle_ticks = 0;
2010
2011    if(demo_man.current_state()==demo_manager::NORMAL && idle_ticks > 420 && demo_start)
2012    {
2013      idle_ticks = 0;
2014      set_state(MENU_STATE);
2015    }
2016    else if(!(dev & EDIT_MODE))               // if edit mode, then don't step anything
2017    {
2018      if(key_down(JK_ESC))
2019      {
2020    set_state(MENU_STATE);
2021    set_key_down(JK_ESC, 0);
2022      }
2023      ambient_ramp = 0;
2024      view *v;
2025      for(v = first_view; v; v = v->next)
2026        v->update_scroll();
2027
2028      cache.prof_poll_start();
2029      current_level->tick();
2030      sbar.step();
2031    } else
2032      dev_scroll();
2033  } else if(state == JOY_CALB_STATE)
2034  {
2035    event ev;
2036    joy_calb(ev);
2037  } else if(state == MENU_STATE)
2038    main_menu();
2039
2040  if((key_down('x') || key_down(JK_F4))
2041      && (key_down(JK_ALT_L) || key_down(JK_ALT_R))
2042      && confirm_quit())
2043    finished = true;
2044}
2045
2046extern void *current_demo;
2047
2048Game::~Game()
2049{
2050  current_demo = NULL;
2051  if(first_view == player_list) first_view = NULL;
2052  while(player_list)
2053  {
2054    view *p = player_list;
2055    game_object *o = p->focus;
2056    player_list = player_list->next;
2057    delete p;
2058    o->set_controller(NULL);
2059    if(current_level && o)
2060      current_level->delete_object(o);
2061    else delete o;
2062  }
2063
2064  if(current_level) { delete current_level; current_level = NULL; }
2065
2066  if(first_view != player_list)
2067  {
2068    while(player_list)
2069    {
2070      view *p = player_list;
2071      player_list = player_list->next;
2072      delete p;
2073    }
2074  }
2075
2076  while(first_view)
2077  {
2078    view *p = first_view;
2079    first_view = first_view->next;
2080    delete p;
2081  }
2082
2083  player_list = NULL;
2084
2085  if(old_view)
2086  {
2087    first_view = old_view;
2088    while(first_view)
2089    {
2090      view *p = first_view;
2091      first_view = first_view->next;
2092      delete p;
2093    }
2094  }
2095  old_view = NULL;
2096
2097  int i = 0;
2098  for(; i < total_objects; i++)
2099  {
2100    free(object_names[i]);
2101    delete figures[i];
2102  }
2103  free_pframes();
2104  delete pal;
2105  free(object_names);
2106  free(figures);
2107
2108  free(backtiles);
2109  free(foretiles);
2110  if(total_weapons)
2111    free(weapon_types);
2112
2113  config_cleanup();
2114  delete color_table;
2115  delete wm;
2116  delete game_font;
2117  delete big_font;
2118  delete console_font;
2119  if(total_help_screens)
2120    free(help_screens);
2121
2122  close_graphics();
2123  image_uninit();
2124}
2125
2126
2127
2128void Game::draw(int scene_mode)
2129{
2130    screen->AddDirty(0, 0, xres + 1, yres + 1);
2131
2132    screen->clear();
2133
2134    if(scene_mode)
2135    {
2136        char const *helpstr = "ARROW KEYS CHANGE TEXT SPEED";
2137        wm->font()->put_string(screen, screen->Size().x/2-(wm->font()->width()*strlen(helpstr))/2 + 1,
2138            screen->Size().y-wm->font()->height()-5 + 1, helpstr, wm->dark_color());
2139        wm->font()->put_string(screen, screen->Size().x/2-(wm->font()->width()*strlen(helpstr))/2,
2140            screen->Size().y-wm->font()->height()-5, helpstr, wm->bright_color());
2141    }
2142/*    else
2143    {
2144        char *helpstr="PRESS h FOR HELP";
2145        wm->font()->put_string(screen, screen->Size().x-wm->font()->width()*strlen(helpstr)-5,
2146            screen->Size().y-wm->font()->height()-5, helpstr);
2147    }*/
2148/*    int dc = cache.img(window_colors)->pixel(0, 2);
2149    int mc = cache.img(window_colors)->pixel(1, 2);
2150    int bc = cache.img(window_colors)->pixel(2, 2);
2151    screen->line(0, 0, screen->Size().x-1, 0, dc);
2152    screen->line(0, 0, 0, screen->Size().y-1, dc);
2153    screen->line(0, screen->Size().y-1, screen->Size().x-1, screen->Size().y-1, bc);
2154    screen->line(screen->Size().x-1, 0, screen->Size().x-1, screen->Size().y-1, bc); */
2155
2156    for(view *f = first_view; f; f = f->next)
2157        draw_map(f, 0);
2158
2159    sbar.redraw(screen);
2160}
2161
2162int external_print = 0;
2163
2164void start_sound(int argc, char **argv)
2165{
2166  sfx_volume = music_volume = 127;
2167
2168  for(int i = 1; i < argc; i++)
2169    if(!strcmp(argv[i], "-sfx_volume"))
2170    {
2171      i++;
2172      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2173        sfx_volume = atoi(argv[i]);
2174      else printf("Bad sound effects volume level, use 0..127\n");
2175    }
2176    else if(!strcmp(argv[i], "-music_volume"))
2177    {
2178      i++;
2179      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2180        music_volume = atoi(argv[i]);
2181      else printf("Bad music volume level, use 0..127\n");
2182    }
2183
2184  sound_avail = sound_init(argc, argv);
2185}
2186
2187void game_printer(char *st)
2188{
2189  if(dev_console && !external_print)
2190  {
2191    dev_console->put_string(st);
2192  }
2193  else fprintf(stderr, "%s", st);
2194}
2195
2196
2197void game_getter(char *st, int max)
2198{
2199  if(!max) return;
2200  max--;
2201  *st = 0;
2202  if(dev_console && !external_print)
2203  {
2204    dev_console->show();
2205    int t = 0;
2206    event ev;
2207    do
2208    {
2209      get_event(ev);
2210      if(ev.type == EV_KEY)
2211      {
2212    if(ev.key == JK_BACKSPACE)
2213    {
2214      if(t)
2215      {
2216        dev_console->print_f("%c", ev.key);
2217        t--;
2218        st--;
2219        *st = 0;
2220        max++;
2221      }
2222    } else if(ev.key>=' ' && ev.key<='~')
2223    {
2224      dev_console->print_f("%c", ev.key);
2225      *st = ev.key;
2226      t++;
2227      max--;
2228      st++;
2229      *st = 0;
2230    }
2231      }
2232      wm->flush_screen();
2233    } while(ev.type != EV_KEY || ev.key != JK_ENTER);
2234    dprintf("\n");
2235  }
2236  else
2237  {
2238    if(fgets(st, max, stdin))
2239    {
2240      if(*st)
2241        st[strlen(st)-1]=0;
2242    }
2243  }
2244}
2245
2246
2247void show_startup()
2248{
2249    dprintf("Abuse version %s\n", PACKAGE_VERSION);
2250}
2251
2252char *get_line(int open_braces)
2253{
2254  char *line=(char *)malloc(1000);
2255  fgets(line, 1000, stdin);
2256
2257  char prev=' ';
2258  for(char *s = line; *s && (prev!=' ' || *s!=';'); s++)
2259  {
2260    prev=*s;
2261    if(*s=='(') open_braces++;
2262    else if(*s==')') open_braces--;
2263  }
2264  if(open_braces < 0)
2265    fprintf(stderr, "\nToo many)'s\n");
2266  else if(open_braces > 0)
2267  {
2268    char *s2 = get_line(open_braces);
2269    line=(char *)realloc(line, strlen(line)+strlen(s2)+1);
2270    strcat(line, s2);
2271    free(s2);
2272  }
2273  return line;
2274}
2275
2276void check_for_lisp(int argc, char **argv)
2277{
2278    for(int i = 1; i < argc; i++)
2279    {
2280        if(!strcmp(argv[i], "-lisp"))
2281        {
2282            lisp_init();
2283            char const *eof_char = "Ctrl-D";
2284            fprintf(stderr,
2285                    " CLIVE (C) 1995 Jonathan Clark, all rights reserved\n"
2286                    "   (C LISP interpreter and various extentions)\n"
2287                    "Type (%s) to exit\n", eof_char);
2288
2289            while(!feof(stdin))
2290            {
2291                fprintf(stderr, "Lisp> ");
2292                char *l = get_line(0);
2293                char const *s = l;
2294                while(*s)
2295                {
2296                    LObject *prog = LObject::Compile(s);
2297                    l_user_stack.push(prog);
2298                    while(*s==' ' || *s=='\t' || *s=='\r' || *s=='\n') s++;
2299                    prog->Eval()->Print();
2300                    l_user_stack.pop(1);
2301                }
2302                free(l);
2303            }
2304            fprintf(stderr, "End of input : bye\n");
2305            exit(0);
2306        }
2307    }
2308}
2309
2310
2311void music_check()
2312{
2313  if(sound_avail & MUSIC_INITIALIZED)
2314  {
2315    if(current_song && !current_song->playing())
2316    {
2317      current_song->play(music_volume);
2318      dprintf("song finished\n");
2319    }
2320    if(!current_song)
2321    {
2322
2323      current_song = new song("music/intro.hmi");
2324      current_song->play(music_volume);
2325
2326/*      if(DEFINEDP(symbol_function(l_next_song)))  // if user function installed, call it to load up next song
2327      {
2328    int sp = current_space;
2329    current_space = PERM_SPACE;
2330    ((LSymbol *)l_next_song)->EvalFunction(NULL);
2331    current_space = sp;
2332      } */
2333    }
2334  }
2335}
2336
2337void setup(int argc, char **argv);
2338
2339void share_end();
2340void show_end();
2341
2342void show_sell(int abortable);
2343
2344extern pmenu *dev_menu;
2345
2346void game_net_init(int argc, char **argv)
2347{
2348#if !defined __CELLOS_LV2__
2349  int nonet=!net_init(argc, argv);
2350  if(nonet)
2351    dprintf("No network driver, or network driver returned failure\n");
2352  else
2353  {
2354    set_file_opener(open_nfs_file);
2355    if(main_net_cfg && main_net_cfg->state == net_configuration::CLIENT)
2356    {
2357      if(set_file_server(net_server))
2358      start_running = 1;
2359      else
2360      {
2361                dprintf("Unable to attach to server, quitting\n");
2362                exit(0);
2363      }
2364    } else
2365    {
2366      int i;
2367      for(i = 1; i < argc - 1; i++)
2368      if(!strcmp(argv[i], "-fs"))
2369      if(!set_file_server(argv[i + 1]))
2370      dprintf("could not set default file server to %s\n", argv[i + 1]);
2371    }
2372  }
2373#endif
2374}
2375
2376int main(int argc, char *argv[])
2377{
2378    start_argc = argc;
2379    start_argv = argv;
2380
2381    for (int i = 0; i < argc; i++)
2382    {
2383        if (!strcmp(argv[i], "-cprint"))
2384            external_print = 1;
2385    }
2386
2387#if (defined(__APPLE__) && !defined(__MACH__))
2388    unsigned char km[16];
2389
2390    fprintf(stderr, "Mac Options: ");
2391    xres = 320; yres = 200;
2392    GetKeys((uint32_t*)&km);
2393    if ((km[ 0x3a >>3] >> (0x3a & 7)) &1 != 0)
2394    {
2395        dev|=EDIT_MODE;
2396        start_edit = 1;
2397        start_running = 1;
2398        disable_autolight = 1;
2399        fprintf(stderr, "Edit Mode...");
2400    }
2401    if ((km[ 0x3b >>3] >> (0x3b & 7)) &1 != 0)
2402    {
2403        PixMult = 1;
2404        fprintf(stderr, "Single Pixel...");
2405    }
2406    else
2407    {
2408        PixMult = 2;
2409        fprintf(stderr, "Double Pixel...");
2410    }
2411    if ((km[ 0x38 >>3] >> (0x38 & 7)) &1 != 0)
2412    {
2413        xres *= 2;  yres *= 2;
2414        fprintf(stderr, "Double Size...");
2415    }
2416    fprintf(stderr, "\n");
2417
2418    if (tcpip.installed())
2419        fprintf(stderr, "Using %s\n", tcpip.name());
2420#endif
2421
2422    set_dprinter(game_printer);
2423    set_dgetter(game_getter);
2424    set_no_space_handler(handle_no_space);
2425
2426    setup(argc, argv);
2427
2428    show_startup();
2429
2430    start_sound(argc, argv);
2431
2432    stat_man = new text_status_manager();
2433
2434#if !defined __CELLOS_LV2__
2435    // look to see if we are supposed to fetch the data elsewhere
2436    if (getenv("ABUSE_PATH"))
2437        set_filename_prefix(getenv("ABUSE_PATH"));
2438
2439    // look to see if we are supposed to save the data elsewhere
2440    if (getenv("ABUSE_SAVE_PATH"))
2441        set_save_filename_prefix(getenv("ABUSE_SAVE_PATH"));
2442#endif
2443
2444    jrand_init();
2445    jrand(); // so compiler doesn't complain
2446
2447    set_spec_main_file("abuse.spe");
2448    check_for_lisp(argc, argv);
2449
2450    do
2451    {
2452        if (main_net_cfg && !main_net_cfg->notify_reset())
2453        {
2454            sound_uninit();
2455            exit(0);
2456        }
2457
2458        game_net_init(argc, argv);
2459        lisp_init();
2460
2461        dev_init(argc, argv);
2462
2463        Game *g = new Game(argc, argv);
2464
2465        dev_cont = new dev_controll();
2466        dev_cont->load_stuff();
2467
2468        g->get_input(); // prime the net
2469
2470#if !defined __CELLOS_LV2__
2471        for (int i = 1; i + 1 < argc; i++)
2472        {
2473            if (!strcmp(argv[i], "-server"))
2474            {
2475                if (!become_server(argv[i + 1]))
2476                {
2477                    dprintf("unable to become a server\n");
2478                    exit(0);
2479                }
2480                break;
2481            }
2482        }
2483
2484        if (main_net_cfg)
2485            wait_min_players();
2486
2487        net_send(1);
2488        if (net_start())
2489        {
2490            g->step(); // process all the objects in the world
2491            g->calc_speed();
2492            g->update_screen(); // redraw the screen with any changes
2493        }
2494#endif
2495
2496        while (!g->done())
2497        {
2498            music_check();
2499
2500            if (req_end)
2501            {
2502                delete current_level; current_level = NULL;
2503
2504                show_end();
2505
2506                the_game->set_state(MENU_STATE);
2507                req_end = 0;
2508            }
2509
2510            if (demo_man.current_state() == demo_manager::NORMAL)
2511                net_receive();
2512
2513            // see if a request for a level load was made during the last tick
2514            if (req_name[0])
2515            {
2516                g->load_level(req_name);
2517                req_name[0] = 0;
2518                g->draw(g->state == SCENE_STATE);
2519            }
2520
2521            //if (demo_man.current_state() != demo_manager::PLAYING)
2522                g->get_input();
2523
2524            if (demo_man.current_state() == demo_manager::NORMAL)
2525                net_send();
2526            else
2527                demo_man.do_inputs();
2528
2529#if !defined __CELLOS_LV2__
2530            service_net_request();
2531#endif
2532
2533            // process all the objects in the world
2534            g->step();
2535#if !defined __CELLOS_LV2__
2536            server_check();
2537#endif
2538            g->calc_speed();
2539
2540            // see if a request for a level load was made during the last tick
2541            if (!req_name[0])
2542                g->update_screen(); // redraw the screen with any changes
2543        }
2544
2545#if !defined __CELLOS_LV2__
2546        net_uninit();
2547
2548        if (net_crcs)
2549            net_crcs->clean_up();
2550        delete net_crcs; net_crcs = NULL;
2551#endif
2552
2553        delete chat;
2554
2555        Timer tmp; tmp.WaitMs(500);
2556
2557        delete small_render; small_render = NULL;
2558
2559        if (current_song)
2560            current_song->stop();
2561        delete current_song; current_song = NULL;
2562
2563        cache.empty();
2564
2565        delete dev_console; dev_console = NULL;
2566        delete dev_menu; dev_menu = NULL;
2567        delete g; g = NULL;
2568        delete old_pal; old_pal = NULL;
2569
2570        compiled_uninit();
2571        delete_all_lights();
2572        free(white_light_initial);
2573
2574        for (int i = 0; i < TTINTS; i++)
2575            free(tints[i]);
2576
2577        dev_cleanup();
2578        delete dev_cont; dev_cont = NULL;
2579        delete stat_man; stat_man = new text_status_manager();
2580
2581        if (!(main_net_cfg && main_net_cfg->restart_state()))
2582        {
2583            LSymbol *end_msg = LSymbol::FindOrCreate("end_msg");
2584            if (DEFINEDP(end_msg->GetValue()))
2585                printf("%s\n", lstring_value(end_msg->GetValue()));
2586        }
2587
2588        lisp_uninit();
2589
2590#if !defined __CELLOS_LV2__
2591        base->packet.packet_reset();
2592#endif
2593    }
2594    while (main_net_cfg && main_net_cfg->restart_state());
2595
2596    delete stat_man;
2597    delete main_net_cfg; main_net_cfg = NULL;
2598
2599    set_filename_prefix(NULL);  // dealloc this mem if there was any
2600    set_save_filename_prefix(NULL);
2601
2602    sound_uninit();
2603
2604    return 0;
2605}
2606
Note: See TracBrowser for help on using the repository browser.