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

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

lisp: refactor Lisp spaces so that they are real objects, and get rid
of the unused USER_SPACE.

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