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

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

game: make the title text scroll both slower and longer.

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