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

Last change on this file since 650 was 650, checked in by Sam Hocevar, 9 years ago

imlib: make some Image methods use vec2i.

File size: 67.1 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->m_surf->bar(dx, dy, dx + jim->Size().x+6, dy + jim->Size().y+6, wm->black());
479        joy_win->m_surf->PutImage(jim, vec2i(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(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      main_screen->GetClip(cx1, cy1, cx2, cy2);
584      main_screen->SetClip(viewx1, viewy1, viewx2 + 1, viewy2 + 1);
585      im->PutImage(main_screen, vec2i((x - xoff / ftile_width())*ftile_width()+viewx1 - xoff % ftile_width(),
586            (y - yoff / ftile_height())*ftile_height()+viewy1 - yoff % ftile_height()));
587      main_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      main_screen->GetClip(cx1, cy1, cx2, cy2);
606      main_screen->SetClip(viewx1, viewy1, viewx2 + 1, viewy2 + 1);
607      main_screen->PutImage(im, vec2i((x - xo / btile_width())*btile_width()+viewx1 - xo % btile_width(),
608            (y - yo / btile_height())*btile_height()+viewy1 - yo % btile_height()), 0);
609      main_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>(main_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>(main_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    main_screen->dirt_off();
701    LSpace::Tmp.Clear();
702    l_post_render->EvalFunction(NULL);
703    LSpace::Tmp.Clear();
704    main_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  main_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        main_screen->SetClip(v->cx1, v->cy1, v->cx2 + 1, v->cy2 + 1);
721      image *tit = cache.img(title_screen);
722      main_screen->PutImage(tit, main_screen->Size() / 2 - tit->Size() / 2);
723      if(state == SCENE_STATE)
724        main_screen->SetClip(cx1, cy1, cx2, cy2);
725      wm->flush_screen();
726    }
727    return;
728  }
729
730  refresh = 0;
731
732
733  // save the dirty rect routines some work by markinging evrything in the
734  // view area dirty alreadt
735
736  if(small_render)
737    main_screen->AddDirty(v->cx1, v->cy1, (v->cx2 - v->cx1 + 1)*2 + v->cx1 + 1, v->cy1+(v->cy2 - v->cy1 + 1)*2 + 1);
738  else
739    main_screen->AddDirty(v->cx1, v->cy1, v->cx2 + 1, v->cy2 + 1);
740
741  if(v->draw_solid != -1)      // fill the screen and exit..
742  {
743    int c = v->draw_solid;
744    main_screen->Lock();
745    for(int y = v->cy1; y <= v->cy2; y++)
746      memset(main_screen->scan_line(y)+v->cx1, c, v->cx2 - v->cx1 + 1);
747    main_screen->Unlock();
748    v->draw_solid = -1;
749    return;
750  }
751
752  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
753  image *old_screen = NULL;
754  if(small_render && (dev & DRAW_LIGHTS))  // cannot do this if we skip lighting
755  {
756    old_cx1 = v->cx1;
757    old_cy1 = v->cy1;
758    old_cx2 = v->cx2;
759    old_cy2 = v->cy2;
760
761    v->cx1 = 0;
762    v->cy1 = 0;
763    v->cx2 = small_render->Size().x-1;
764    v->cy2 = small_render->Size().y-1;
765
766    old_screen = main_screen;
767    main_screen = small_render;
768  } else
769    main_screen->dirt_off();
770
771
772  int32_t xoff, yoff;
773  if(interpolate)
774  {
775    xoff = v->interpolated_xoff();
776    yoff = v->interpolated_yoff();
777  } else
778  {
779    xoff = v->xoff();
780    yoff = v->yoff();
781  }
782
783//  if(xoff > max_xoff) xoff = max_xoff;
784//  if(yoff > max_yoff) yoff = max_yoff;
785
786  current_vxadd = xoff - v->cx1;
787  current_vyadd = yoff - v->cy1;
788
789  main_screen->SetClip(v->cx1, v->cy1, v->cx2 + 1, v->cy2 + 1);
790
791  nxoff = xoff * bg_xmul / bg_xdiv;
792  nyoff = yoff * bg_ymul / bg_ydiv;
793
794
795  x1 = nxoff / btile_width(); y1 = nyoff / btile_height();
796  x2 = x1+(v->cx2 - v->cx1 + btile_width())/btile_width();
797  y2 = y1+(v->cy2 - v->cy1 + btile_height())/btile_height();
798
799
800  xo = v->cx1 - nxoff % btile_width();
801  yo = v->cy1 - nyoff % btile_height();
802
803  int xinc, yinc, draw_x, draw_y;
804
805
806  if(!(dev & MAP_MODE) && (dev & DRAW_BG_LAYER))
807  {
808    xinc = btile_width();
809    yinc = btile_height();
810
811    int bh = current_level->background_height(), bw = current_level->background_width();
812    uint16_t *bl;
813    for(draw_y = yo, y = y1; y <= y2; y++, draw_y += yinc)
814    {
815      if(y >= bh)
816        bl = NULL;
817      else
818        bl = current_level->get_bgline(y)+x1;
819
820      for(x = x1, draw_x = xo; x <= x2; x++, draw_x += xinc)
821      {
822    if(x < bw && y < bh)
823    {
824          bt = get_bg(*bl);
825      bl++;
826    }
827    else bt = get_bg(0);
828
829        main_screen->PutImage(bt->im, vec2i(draw_x, draw_y));
830//        if(!(dev & EDIT_MODE) && bt->next)
831//      current_level->put_bg(x, y, bt->next);
832      }
833    }
834  }
835
836//  if(!(dev & EDIT_MODE))
837//    server_check();
838
839  uint8_t rescan = 0;
840
841    int fw, fh;
842
843    if(dev & MAP_MODE)
844    {
845      fw = AUTOTILE_WIDTH;
846      fh = AUTOTILE_HEIGHT;
847      if(dev & EDIT_MODE)
848      {
849    x1 = map_xoff;
850    y1 = map_yoff;
851      } else
852      {
853    if(v->focus)
854    {
855      x1 = v->focus->x / ftile_width()-(v->cx2 - v->cx1)/fw / 2;
856      y1 = v->focus->y / ftile_height()-(v->cy2 - v->cy1)/fh / 2;
857    } else x1 = y1 = 0;
858      }
859      if(x1 > 0)
860        xo = v->cx1-((v->focus->x * fw / ftile_width()) %fw);
861      else xo = v->cx1;
862      if(y1 > 0)
863        yo = v->cy1-((v->focus->y * fh / ftile_height()) %fh);
864      else yo = v->cy1;
865    } else
866    {
867      fw = ftile_width();
868      fh = ftile_height();
869      x1=(xoff)/fw; y1=(yoff)/fh;
870      xo = v->cx1 - xoff % fw;
871      yo = v->cy1 - yoff % fh;
872
873    }
874    if(x1 < 0) x1 = 0;
875    if(y1 < 0) y1 = 0;
876
877    x2 = x1+(v->cx2 - v->cx1 + fw)/fw;
878    y2 = y1+(v->cy2 - v->cy1 + fh)/fh;
879    if(x2 >= current_level->foreground_width())
880      x2 = current_level->foreground_width()-1;
881    if(y2 >= current_level->foreground_height())
882      y2 = current_level->foreground_height()-1;
883
884
885    xinc = fw;
886    yinc = fh;
887
888  if(dev & DRAW_FG_LAYER)
889  {
890    int ncx1, ncy1, ncx2, ncy2;
891    main_screen->GetClip(ncx1, ncy1, ncx2, ncy2);
892
893    int scr_w = main_screen->Size().x;
894    if(dev & MAP_MODE)
895    {
896      if(dev & EDIT_MODE)
897        main_screen->clear(wm->bright_color());
898      else
899        main_screen->clear(wm->black());
900      main_screen->Lock();
901      for(y = y1, draw_y = yo; y <= y2; y++, draw_y += yinc)
902      {
903    if(!(draw_y < ncy1 ||draw_y + yinc > ncy2))
904    {
905      uint16_t *cl = current_level->get_fgline(y)+x1;
906      uint8_t *sl1 = main_screen->scan_line(draw_y)+xo;
907      for(x = x1, draw_x = xo; x <= x2; x++, cl++, sl1 += xinc, draw_x += xinc)
908      {
909        if(!(draw_x < ncx1 || draw_x + xinc > ncx2))
910        {
911          int fort_num;
912//          if(*cl & 0x8000 || (dev & EDIT_MODE))
913            fort_num = fgvalue(*cl);
914//          else fort_num = 0;
915
916          uint8_t *sl2 = get_fg(fort_num)->micro_image->scan_line(0);
917          uint8_t *sl3 = sl1;
918          memcpy(sl3, sl2, AUTOTILE_WIDTH); sl2 += AUTOTILE_WIDTH; sl3 += scr_w;
919          memcpy(sl3, sl2, AUTOTILE_WIDTH); sl2 += AUTOTILE_WIDTH; sl3 += scr_w;
920          memcpy(sl3, sl2, AUTOTILE_WIDTH);
921        }
922      }
923    }
924      }
925      main_screen->Unlock();
926
927      if(dev & EDIT_MODE)
928        current_level->draw_areas(v);
929    } else
930    {
931
932      int fg_h = current_level->foreground_height(), fg_w = current_level->foreground_width();
933
934      for(y = y1, draw_y = yo; y <= y2; y++, draw_y += yinc)
935      {
936
937    uint16_t *cl;
938    if(y < fg_h)
939      cl = current_level->get_fgline(y)+x1;
940    else cl = NULL;
941
942    for(x = x1, draw_x = xo; x <= x2; x++, draw_x += xinc, cl++)
943    {
944      if(x < fg_w && y < fg_h)
945      {
946        if(above_tile(*cl))
947        rescan = 1;
948        else
949        {
950          int fort_num = fgvalue(*cl);
951          if(fort_num != BLACK)
952          {
953            get_fg(fort_num)->im->PutImage(main_screen, vec2i(draw_x, draw_y));
954
955        if(!(dev & EDIT_MODE))
956            *cl|=0x8000;      // mark as has - been - seen
957          }
958        }
959      }
960    }
961      }
962    }
963  }
964
965  int32_t ro = rand_on;
966  if(dev & DRAW_PEOPLE_LAYER)
967  {
968    if(interpolate)
969      current_level->interpolate_draw_objects(v);
970    else
971      current_level->draw_objects(v);
972  }
973
974//  if(!(dev & EDIT_MODE))
975//    server_check();
976
977  if(!(dev & MAP_MODE))
978  {
979
980    draw_panims(v);
981
982    if(dev & DRAW_FG_LAYER && rescan)
983    {
984      for(y = y1, draw_y = yo; y <= y2; y++, draw_y += yinc)
985      {
986    uint16_t *cl = current_level->get_fgline(y)+x1;
987    for(x = x1, draw_x = xo; x <= x2; x++, draw_x += xinc, cl++)
988    {
989      if(above_tile(*cl))
990      {
991        int fort_num = fgvalue(*cl);
992        if(fort_num != BLACK)
993        {
994          if(dev & DRAW_BG_LAYER)
995          get_fg(fort_num)->im->PutImage(main_screen, vec2i(draw_x, draw_y));
996          else
997          get_fg(fort_num)->im->PutFilled(main_screen, vec2i(draw_x, draw_y), 0);
998
999          if(!(dev & EDIT_MODE))
1000          current_level->mark_seen(x, y);
1001          else
1002          {
1003        main_screen->line(draw_x, draw_y, draw_x + xinc, draw_y + yinc, wm->bright_color());
1004        main_screen->line(draw_x + xinc, draw_y, draw_x, draw_y + yinc, wm->bright_color());
1005          }
1006        }
1007      }
1008    }
1009      }
1010    }
1011
1012
1013    if(dev & DRAW_FG_BOUND_LAYER)
1014    {
1015      int b = wm->bright_color();
1016      int fg_h = current_level->foreground_height(), fg_w = current_level->foreground_width();
1017
1018      for(y = y1, draw_y = yo; y <= y2; y++, draw_y += yinc)
1019      {
1020    uint16_t *cl;
1021    if(y < fg_h)
1022      cl = current_level->get_fgline(y)+x1;
1023    else cl = NULL;
1024    for(x = x1, draw_x = xo; x <= x2; x++, draw_x += xinc, cl++)
1025    {
1026      if(x < fg_w && y < fg_h)
1027      {
1028        int fort_num = fgvalue(*cl);
1029        if(fort_num != BLACK)
1030        {
1031          point_list *p = get_fg(fort_num)->points;
1032          uint8_t *d = p->data;
1033          if(p->tot)
1034          {
1035        for(int i = 1; i < p->tot; i++)
1036        {
1037          d += 2;
1038          main_screen->line(draw_x+*(d - 2), draw_y+*(d - 1), draw_x+*d, draw_y+*(d + 1), b);
1039        }
1040        main_screen->line(draw_x+*d, draw_y+*(d - 1), draw_x + p->data[0], draw_y + p->data[1], b);
1041          }
1042        }
1043      }
1044    }
1045      }
1046    }
1047
1048//    if(!(dev & EDIT_MODE))
1049//      server_check();
1050
1051    if(dev & DRAW_HELP_LAYER)
1052    {
1053      if(help_text_frames >= 0)
1054      {
1055    int color;
1056
1057    if(help_text_frames < 10)
1058        color = 2;
1059    else
1060        color = 2+(help_text_frames - 10);
1061
1062    int x1 = v->cx1, y1 = v->cy1, x2 = v->cx2, y2 = v->cy1 + wm->font()->height()+10;
1063
1064    remap_area(main_screen, x1, y1, x2, y2, white_light + 40 * 256);
1065    main_screen->bar(x1, y1, x2, y1, color);
1066    main_screen->bar(x1, y2, x2, y2, color);
1067
1068    wm->font()->put_string(main_screen, x1 + 5, y1 + 5,
1069                   help_text, color);
1070    if(color > 30)
1071        help_text_frames = -1;
1072    else help_text_frames++;
1073
1074      }
1075    }
1076
1077    if(dev_cont)
1078    dev_cont->dev_draw(v);
1079    if(cache.in_use())
1080    main_screen->PutImage(cache.img(vmm_image), vec2i(v->cx1, v->cy2 - cache.img(vmm_image)->Size().y+1));
1081
1082    if(dev & DRAW_LIGHTS)
1083    {
1084      if(small_render)
1085      {
1086    double_light_screen(main_screen, xoff, yoff, white_light, v->ambient, old_screen, old_cx1, old_cy1);
1087
1088    v->cx1 = old_cx1;
1089    v->cy1 = old_cy1;
1090    v->cx2 = old_cx2;
1091    v->cy2 = old_cy2;
1092    main_screen = old_screen;
1093      } else
1094      {
1095    main_screen->dirt_on();
1096    if(xres * yres <= 64000)
1097          light_screen(main_screen, xoff, yoff, white_light, v->ambient);
1098    else light_screen(main_screen, xoff, yoff, white_light, 63);            // no lighting for hi - rez
1099      }
1100
1101    } else
1102      main_screen->dirt_on();
1103
1104
1105
1106  }  else
1107    main_screen->dirt_on();
1108
1109  rand_on = ro;                // restore random start in case in draw funs moved it
1110                               // ... not every machine will draw the same thing
1111
1112  post_render();
1113
1114  main_screen->SetClip(cx1, cy1, cx2 + 1, cy2 + 1);
1115
1116
1117
1118
1119  if(playing_state(state))        // draw stuff outside the clipping region
1120    v->draw_character_damage();
1121
1122  if(profiling())
1123    profile_update();
1124
1125  sbar.draw_update();
1126}
1127
1128void Game::put_fg(int x, int y, int type)
1129{
1130  if(current_level->get_fg(x, y)!=type)
1131  {
1132    current_level->put_fg(x, y, type);
1133    for(view *f = first_view; f; f = f->next)
1134      if(f->drawable())
1135        draw_map(f);
1136  }
1137}
1138
1139void Game::put_bg(int x, int y, int type)
1140{
1141  if(current_level->get_bg(x, y)!=type)
1142  {
1143    current_level->put_bg(x, y, type);
1144    for(view *f = first_view; f; f = f->next)
1145      if(f->drawable())
1146        draw_map(f);
1147  }
1148}
1149
1150int Game::in_area(Event &ev, int x1, int y1, int x2, int y2)
1151{
1152  return (last_demo_mx >= x1 && last_demo_mx <= x2 &&
1153      last_demo_my >= y1 && last_demo_my <= y2);
1154}
1155
1156void Game::request_level_load(char *name)
1157{
1158  strcpy(req_name, name);
1159}
1160
1161extern int start_doubled;
1162
1163template<int N> static void Fade(image *im, int steps)
1164{
1165    /* 25ms per step */
1166    float const duration = 25.f;
1167
1168    palette *old_pal = pal->copy();
1169
1170    if (im)
1171    {
1172        main_screen->clear();
1173        main_screen->PutImage(im, vec2i(xres + 1, yres + 1) / 2
1174                                   - im->Size() / 2);
1175    }
1176
1177    for (Timer total; total.PollMs() < duration * steps; )
1178    {
1179        Timer frame;
1180        uint8_t *sl1 = (uint8_t *)pal->addr();
1181        uint8_t *sl2 = (uint8_t *)old_pal->addr();
1182        int i = (int)(total.PollMs() / duration);
1183        int v = (N ? i + 1 : steps - i) * 256 / steps;
1184
1185        for (int j = 0; j < 3 * 256; j++)
1186            *sl1++ = (int)*sl2++ * v / 256;
1187
1188        pal->load();
1189        wm->flush_screen();
1190        frame.WaitMs(duration);
1191    }
1192
1193    if (N == 0)
1194    {
1195        main_screen->clear();
1196        wm->flush_screen();
1197        old_pal->load();
1198    }
1199    delete pal;
1200    pal = old_pal;
1201}
1202
1203void fade_in(image *im, int steps)
1204{
1205    Fade<1>(im, steps);
1206}
1207
1208void fade_out(int steps)
1209{
1210    Fade<0>(NULL, steps);
1211}
1212
1213int text_draw(int y, int x1, int y1, int x2, int y2, char const *buf, JCFont *font, uint8_t *cmap, char color);
1214
1215void do_title()
1216{
1217    if(cdc_logo == -1)
1218        return;
1219
1220    if(sound_avail & MUSIC_INITIALIZED)
1221    {
1222        if(current_song)
1223        {
1224            current_song->stop();
1225            delete current_song;
1226        }
1227        current_song = new song("music/intro.hmi");
1228        current_song->play(music_volume);
1229    }
1230
1231    void *logo_snd = LSymbol::FindOrCreate("LOGO_SND")->GetValue();
1232
1233    if(DEFINEDP(logo_snd) && (sound_avail & SFX_INITIALIZED))
1234        cache.sfx(lnumber_value(logo_snd))->play(sfx_volume);
1235
1236    // This must be a dynamic allocated image because if it
1237    // is not and the window gets closed during do_title, then
1238    // exit() will try to delete (through the desctructor of
1239    // image_list in image.cpp) the image on the stack -> boom.
1240    image *blank = new image(vec2i(2, 2));
1241    blank->clear();
1242    wm->set_mouse_shape(blank->copy(), 0, 0); // hide mouse
1243    delete blank;
1244    fade_in(cache.img(cdc_logo), 32);
1245    Timer tmp; tmp.WaitMs(400);
1246    fade_out(32);
1247
1248    void *space_snd = LSymbol::FindOrCreate("SPACE_SND")->GetValue();
1249    char *str = lstring_value(LSymbol::FindOrCreate("plot_start")->Eval());
1250
1251    bFILE *fp = open_file("art/smoke.spe", "rb");
1252    if(!fp->open_failure())
1253    {
1254        spec_directory sd(fp);
1255        palette *old_pal = pal;
1256        pal = new palette(sd.find(SPEC_PALETTE), fp);
1257        pal->shift(1);
1258
1259        image *gray = new image(fp, sd.find("gray_pict"));
1260        image *smoke[5];
1261
1262        char nm[20];
1263        for (int i = 0; i < 5; i++)
1264        {
1265            sprintf(nm, "smoke%04d.pcx", i + 1);
1266            smoke[i] = new image(fp, sd.find(nm));
1267        }
1268
1269        main_screen->clear();
1270        pal->load();
1271
1272        int dx = (xres + 1) / 2 - gray->Size().x / 2, dy = (yres + 1) / 2 - gray->Size().y / 2;
1273        main_screen->PutImage(gray, vec2i(dx, dy));
1274        main_screen->PutImage(smoke[0], vec2i(dx + 24, dy + 5));
1275
1276        fade_in(NULL, 16);
1277        uint8_t cmap[32];
1278        for(int i = 0; i < 32; i++)
1279        cmap[i] = pal->find_closest(i * 256 / 32, i * 256 / 32, i * 256 / 32);
1280
1281        Event ev;
1282        ev.type = EV_SPURIOUS;
1283        Timer total;
1284
1285        while (ev.type != EV_KEY && ev.type != EV_MOUSE_BUTTON)
1286        {
1287            Timer frame;
1288
1289            // 120 ms per step
1290            int i = (int)(total.PollMs() / 120.f);
1291            if (i >= 400)
1292                break;
1293
1294            main_screen->PutImage(gray, vec2i(dx, dy));
1295            main_screen->PutImage(smoke[i % 5], vec2i(dx + 24, dy + 5));
1296            text_draw(205 - i, dx + 15, dy, dx + 320 - 15, dy + 199, str, wm->font(), cmap, wm->bright_color());
1297            wm->flush_screen();
1298            time_marker now;
1299
1300            while(wm->IsPending() && ev.type != EV_KEY)
1301                wm->get_event(ev);
1302
1303            if((i % 5) == 0 && DEFINEDP(space_snd) && (sound_avail & SFX_INITIALIZED))
1304                cache.sfx(lnumber_value(space_snd))->play(sfx_volume * 90 / 127);
1305
1306            frame.WaitMs(25.f);
1307            frame.GetMs();
1308        }
1309
1310        the_game->reset_keymap();
1311
1312        fade_out(16);
1313
1314        for (int i = 0; i < 5; i++)
1315            delete smoke[i];
1316        delete gray;
1317        delete pal;
1318        pal = old_pal;
1319    }
1320    delete fp;
1321
1322    if(title_screen >= 0)
1323        fade_in(cache.img(title_screen), 32);
1324}
1325
1326extern int start_edit;
1327
1328void Game::request_end()
1329{
1330  req_end = 1;
1331}
1332
1333Game::Game(int argc, char **argv)
1334{
1335  int i;
1336  req_name[0]=0;
1337  bg_xmul = bg_ymul = 1;
1338  bg_xdiv = bg_ydiv = 8;
1339  last_input = NULL;
1340  current_automap = NULL;
1341  current_level = NULL;
1342  refresh = 1;
1343  the_game = this;
1344  top_menu = joy_win = NULL;
1345  old_view = first_view = NULL;
1346  nplayers = 1;
1347
1348  help_text_frames = 0;
1349  strcpy(help_text, "");
1350
1351
1352  for(i = 1; i < argc; i++)
1353    if(!strcmp(argv[i], "-no_delay"))
1354    {
1355      no_delay = 1;
1356      dprintf("Frame delay off (-nodelay)\n");
1357    }
1358
1359
1360  image_init();
1361  zoom = 15;
1362  no_delay = 0;
1363
1364  if(get_option("-use_joy"))
1365  {
1366    has_joystick = joy_init(argc, argv);
1367    dprintf("Joystick : ");
1368    if(has_joystick) dprintf("detected\n");
1369    else dprintf("not detected\n");
1370  }
1371  else has_joystick = 0;
1372
1373    // Clean up that old crap
1374    char *fastpath = (char *)malloc(strlen(get_save_filename_prefix()) + 13);
1375    sprintf(fastpath, "%sfastload.dat", get_save_filename_prefix());
1376    unlink(fastpath);
1377    free(fastpath);
1378
1379//    ProfilerInit(collectDetailed, bestTimeBase, 2000, 200); //prof
1380    load_data(argc, argv);
1381//    ProfilerDump("\pabuse.prof");  //prof
1382//    ProfilerTerm();
1383
1384  get_key_bindings();
1385
1386  reset_keymap();                   // we think all the keys are up right now
1387  finished = false;
1388
1389  calc_light_table(pal);
1390
1391#if !defined __CELLOS_LV2__
1392  if(current_level == NULL && net_start())  // if we joined a net game get level from server
1393  {
1394    if(!request_server_entry())
1395    {
1396      exit(0);
1397    }
1398    net_reload();
1399//    load_level(NET_STARTFILE);
1400  }
1401#endif
1402
1403  set_mode(19, argc, argv);
1404  if(get_option("-2") && (xres < 639 || yres < 399))
1405  {
1406    close_graphics();
1407    fprintf(stderr, "Resolution must be > 640x400 to use -2 option\n");
1408    exit(0);
1409  }
1410  pal->load();
1411
1412  recalc_local_view_space();   // now that we know what size the screen is...
1413
1414  dark_color = get_color(cache.img(window_colors)->Pixel(vec2i(2, 0)));
1415  bright_color = get_color(cache.img(window_colors)->Pixel(vec2i(0, 0)));
1416  med_color = get_color(cache.img(window_colors)->Pixel(vec2i(1, 0)));
1417
1418  morph_dark_color = get_color(cache.img(window_colors)->Pixel(vec2i(2, 1)));
1419  morph_bright_color = get_color(cache.img(window_colors)->Pixel(vec2i(0, 1)));
1420  morph_med_color = get_color(cache.img(window_colors)->Pixel(vec2i(1, 1)));
1421  morph_sel_frame_color = pal->find_closest(255, 255, 0);
1422  light_connection_color = morph_sel_frame_color;
1423
1424  if(NILP(symbol_value(l_default_font)))
1425  {
1426    printf("No font defined, set symbol default-font to an image name\n");
1427    exit(0);
1428  }
1429  int font_pict;
1430  if(big_font_pict != -1)
1431  {
1432    if(small_font_pict != -1)
1433    {
1434      if(xres/(start_doubled ? 2 : 1)>400)
1435      {
1436    font_pict = big_font_pict;
1437      }
1438      else font_pict = small_font_pict;
1439    } else font_pict = big_font_pict;
1440  } else font_pict = small_font_pict;
1441
1442  if(console_font_pict == -1) console_font_pict = font_pict;
1443  game_font = new JCFont(cache.img(font_pict));
1444
1445  console_font = new JCFont(cache.img(console_font_pict));
1446
1447  wm = new WindowManager(main_screen, pal, bright_color,
1448                         med_color, dark_color, game_font);
1449
1450  delete stat_man;  // move to a graphical status manager
1451  gui_status_manager *gstat = new gui_status_manager();
1452  gstat->set_window_title("status");
1453  stat_man = gstat;
1454
1455
1456  chat = new chat_console( console_font, 50, 6);
1457
1458  if(!wm->has_mouse())
1459  {
1460    close_graphics();
1461    image_uninit();
1462    printf("No mouse driver detected, please rectify.\n");
1463    exit(0);
1464  }
1465
1466  gamma_correct(pal);
1467
1468#if defined __CELLOS_LV2__
1469  if(!start_edit)
1470    do_title();
1471#else
1472  if(main_net_cfg == NULL || (main_net_cfg->state != net_configuration::SERVER &&
1473                 main_net_cfg->state != net_configuration::CLIENT))
1474  {
1475    if(!start_edit && !net_start())
1476      do_title();
1477  } else if(main_net_cfg && main_net_cfg->state == net_configuration::SERVER)
1478  {
1479    the_game->load_level(level_file);
1480    start_running = 1;
1481  }
1482#endif
1483
1484
1485  dev|= DRAW_FG_LAYER | DRAW_BG_LAYER | DRAW_PEOPLE_LAYER | DRAW_HELP_LAYER | DRAW_LIGHTS | DRAW_LINKS;
1486
1487  if(dev & EDIT_MODE)
1488    set_frame_size(0);
1489//  do_intro();
1490  state = START_STATE;         // first set the state to one that has windows
1491
1492
1493  if(start_running)
1494    set_state(RUN_STATE);
1495  else
1496  {
1497    main_screen->clear();
1498    if(title_screen >= 0)
1499    {
1500      image *im = cache.img(title_screen);
1501      main_screen->PutImage(im, main_screen->Size() / 2 - im->Size() / 2);
1502    }
1503    set_state(MENU_STATE);   // then go to menu state so windows will turn off
1504  }
1505}
1506
1507time_marker *led_last_time = NULL;
1508static float avg_ms = 1000.0f / 15, possible_ms = 1000.0f / 15;
1509
1510void Game::toggle_delay()
1511{
1512    no_delay = !no_delay;
1513    show_help(symbol_str(no_delay ? "delay_off" : "delay_on"));
1514    avg_ms = possible_ms = 1000.0f / 15;
1515}
1516
1517void Game::show_time()
1518{
1519    if (!first_view || !fps_on)
1520        return;
1521
1522    char str[16];
1523    sprintf(str, "%ld", (long)(10000.0f / avg_ms));
1524    console_font->put_string(main_screen, first_view->cx1, first_view->cy1, str);
1525
1526    sprintf(str, "%d", total_active);
1527    console_font->put_string(main_screen, first_view->cx1, first_view->cy1 + 10, str);
1528}
1529
1530void Game::update_screen()
1531{
1532  if(state == HELP_STATE)
1533    draw_help();
1534  else if(current_level)
1535  {
1536    if(!(dev & EDIT_MODE) || refresh)
1537    {
1538      view *f = first_view;
1539      current_level->clear_active_list();
1540      for(; f; f = f->next)
1541      {
1542    if(f->focus)
1543    {
1544      int w, h;
1545
1546      w=(f->cx2 - f->cx1 + 1);
1547      h=(f->cy2 - f->cy1 + 1);
1548
1549      total_active += current_level->add_drawables(f->xoff()-w / 4, f->yoff()-h / 4,
1550                             f->xoff()+w + w / 4, f->yoff()+h + h / 4);
1551
1552    }
1553      }
1554
1555      for(f = first_view; f; f = f->next)
1556      {
1557        if(f->drawable())
1558    {
1559      if(interpolate_draw)
1560      {
1561            draw_map(f, 1);
1562        wm->flush_screen();
1563      }
1564          draw_map(f, 0);
1565    }
1566      }
1567      if(current_automap)
1568      current_automap->draw();
1569    }
1570    if(state == PAUSE_STATE)
1571    {
1572      for(view *f = first_view; f; f = f->next)
1573        main_screen->PutImage(cache.img(pause_image), vec2i((f->cx1 + f->cx2)/2 - cache.img(pause_image)->Size().x/2,
1574                   f->cy1 + 5), 1);
1575    }
1576
1577    show_time();
1578  }
1579
1580  if(state == RUN_STATE && cache.prof_is_on())
1581    cache.prof_poll_end();
1582
1583  wm->flush_screen();
1584
1585}
1586
1587void Game::do_intro()
1588{
1589
1590}
1591
1592// FIXME: refactor this to use the Lol Engine main fixed-framerate loop?
1593int Game::calc_speed()
1594{
1595    static Timer frame_timer;
1596    static int first = 1;
1597
1598    if (first)
1599    {
1600        first = 0;
1601        return 0;
1602    }
1603
1604    // Find average fps for last 10 frames
1605    float deltams = Max(1.0f, frame_timer.PollMs());
1606
1607    avg_ms = 0.9f * avg_ms + 0.1f * deltams;
1608    possible_ms = 0.9f * possible_ms + 0.1f * deltams;
1609
1610    if (avg_ms < 1000.0f / 14)
1611        massive_frame_panic = Max(0, Min(20, massive_frame_panic - 1));
1612
1613    int ret = 0;
1614
1615    if (dev & EDIT_MODE)
1616    {
1617        // ECS - Added this case and the wait.  It's a cheap hack to ensure
1618        // that we don't exceed 30FPS in edit mode and hog the CPU.
1619        frame_timer.WaitMs(33);
1620    }
1621    else if (avg_ms < 1000.0f / 15 && need_delay)
1622    {
1623        frame_panic = 0;
1624        if (!no_delay)
1625        {
1626            frame_timer.WaitMs(1000.0f / 15);
1627            avg_ms -= 0.1f * deltams;
1628            avg_ms += 0.1f * 1000.0f / 15;
1629        }
1630    }
1631    else if (avg_ms > 1000.0f / 14)
1632    {
1633        if(avg_ms > 1000.0f / 10)
1634            massive_frame_panic++;
1635        frame_panic++;
1636        // All is lost, don't sleep during this frame
1637        ret = 1;
1638    }
1639
1640    // Ignore our wait time, we're more interested in the frame time
1641    frame_timer.GetMs();
1642    return ret;
1643}
1644
1645extern int start_edit;
1646
1647void Game::get_input()
1648{
1649    Event ev;
1650    idle_ticks++;
1651    while(event_waiting())
1652    {
1653        get_event(ev);
1654
1655        if(ev.type == EV_MOUSE_MOVE)
1656        {
1657            last_input = ev.window;
1658        }
1659        // don't process repeated keys in the main window, it will slow down the game to handle such
1660        // useless events. However in other windows it might be useful, such as in input windows
1661        // where you want to repeatedly scroll down...
1662        if(ev.type != EV_KEY || !key_down(ev.key) || ev.window || (dev & EDIT_MODE))
1663        {
1664#if !defined __CELLOS_LV2__
1665            if(ev.type == EV_KEY)
1666            {
1667                set_key_down(ev.key, 1);
1668                if(playing_state(state))
1669                {
1670                    if(ev.key < 256)
1671                    {
1672                        if(chat && chat->chat_event(ev))
1673                            base->packet.write_uint8(SCMD_CHAT_KEYPRESS);
1674                        else
1675                            base->packet.write_uint8(SCMD_KEYPRESS);
1676                    }
1677                    else
1678                        base->packet.write_uint8(SCMD_EXT_KEYPRESS);
1679                    base->packet.write_uint8(client_number());
1680                    if(ev.key > 256)
1681                        base->packet.write_uint8(ev.key - 256);
1682                    else
1683                        base->packet.write_uint8(ev.key);
1684                }
1685            }
1686            else if(ev.type == EV_KEYRELEASE)
1687            {
1688                set_key_down(ev.key, 0);
1689                if(playing_state(state))
1690                {
1691                    if(ev.key < 256)
1692                        base->packet.write_uint8(SCMD_KEYRELEASE);
1693                    else
1694                        base->packet.write_uint8(SCMD_EXT_KEYRELEASE);
1695                    base->packet.write_uint8(client_number());
1696                    if(ev.key > 255)
1697                        base->packet.write_uint8(ev.key - 256);
1698                    else
1699                        base->packet.write_uint8(ev.key);
1700                }
1701            }
1702#endif
1703
1704            if((dev & EDIT_MODE) || start_edit || ev.type == EV_MESSAGE)
1705            {
1706                dev_cont->handle_event(ev);
1707            }
1708
1709            view *v = first_view;
1710            for(; v; v = v->next)
1711            {
1712                if(v->local_player() && v->handle_event(ev))
1713                    ev.type = EV_SPURIOUS;       // if the Event was used by the view, gobble it up
1714            }
1715
1716            if(current_automap)
1717            {
1718                current_automap->handle_event(ev);
1719            }
1720
1721            help_handle_event(ev);
1722            mousex = last_demo_mx;
1723            mousey = last_demo_my;
1724
1725            if(ev.type == EV_MESSAGE)
1726            {
1727                switch (ev.message.id)
1728                {
1729                    case CALB_JOY:
1730                    {
1731                        if(!joy_win)
1732                        {
1733                            joy_win = wm->new_window(80, 50, -1, -1,
1734                                    new button(70, 9, JOY_OK, "OK",
1735                                    new info_field(0, 30, DEV_NULL,
1736                                    " Center joystick and\n"
1737                                    "press the fire button", NULL)),
1738                                    "Joystick");
1739                            set_state(JOY_CALB_STATE);
1740                        }
1741                    }
1742                    case TOP_MENU:
1743                    {
1744                        menu_select(ev);
1745                    } break;
1746                    case DEV_QUIT:
1747                    {
1748                        finished = true;
1749                    } break;
1750                }
1751            }
1752            else if(ev.type == EV_CLOSE_WINDOW && ev.window == top_menu)
1753            {
1754                wm->close_window(top_menu);
1755                top_menu = NULL;
1756            }
1757
1758            switch(state)
1759            {
1760                case JOY_CALB_STATE:
1761                {
1762                    joy_calb(ev);
1763                } break;
1764                case INTRO_START_STATE:
1765                {
1766                    do_intro();
1767                    if(dev & EDIT_MODE)
1768                        set_state(RUN_STATE);
1769                    else
1770                        set_state(MENU_STATE);
1771                } break;
1772                case PAUSE_STATE:
1773                {
1774                    if(ev.type == EV_KEY && (ev.key == JK_SPACE || ev.key == JK_ENTER))
1775                    {
1776                        set_state(RUN_STATE);
1777                    }
1778                } break;
1779                case RUN_STATE:
1780                {
1781                    if(ev.window == NULL)
1782                    {
1783                        switch (ev.type)
1784                        {
1785                            case EV_KEY:
1786                            {
1787                                switch (ev.key)
1788                                {
1789                                    case 'm':
1790                                    {
1791                                        if(dev & MAP_MODE)
1792                                            dev -= MAP_MODE;
1793                                        else if((player_list && player_list->next) || dev & EDIT_MODE)
1794                                            dev |= MAP_MODE;
1795
1796                                        if(!(dev & MAP_MODE))
1797                                        {
1798                                            if(dev_cont->tbw)
1799                                                dev_cont->toggle_toolbar();
1800                                            edit_mode = ID_DMODE_DRAW;
1801                                        }
1802                                        need_refresh();
1803                                    } break;
1804                                    case 'v':
1805                                    {
1806                                        wm->Push(new Event(DO_VOLUME, NULL));
1807                                    } break;
1808                                    case 'p':
1809                                    {
1810                                        if(!(dev & EDIT_MODE) && (!main_net_cfg ||
1811                                            (main_net_cfg->state != net_configuration::SERVER &&
1812                                            main_net_cfg->state != net_configuration::CLIENT)))
1813                                        {
1814                                            set_state(PAUSE_STATE);
1815                                        }
1816                                    } break;
1817                                    case 'S':
1818                                    {
1819                                        if(start_edit)
1820                                        {
1821                                            wm->Push(new Event(ID_LEVEL_SAVE, NULL));
1822                                        }
1823                                    } break;
1824                                    case JK_TAB:
1825                                        if(start_edit)
1826                                            toggle_edit_mode();
1827                                        need_refresh();
1828                                        break;
1829                                    case 'c':
1830                                    case 'C':
1831                                        if(chatting_enabled && (!(dev & EDIT_MODE) && chat))
1832                                            chat->toggle();
1833                                        break;
1834                                    case '9':
1835                                        dev = dev ^ PERFORMANCE_TEST_MODE;
1836                                        need_refresh();
1837                                        break;
1838                                }
1839                            } break;
1840                            case EV_RESIZE:
1841                            {
1842                                view *v;
1843                                for(v = first_view; v; v = v->next)  // see if any views need to change size
1844                                {
1845                                    if(v->local_player())
1846                                    {
1847                                        int w = (xres - 10)/(small_render ? 2 : 1);
1848                                        int h = (yres - 10)/(small_render ? 2 : 1);
1849
1850                                        v->suggest.send_view = 1;
1851                                        v->suggest.cx1 = 5;
1852                                        v->suggest.cx2 = 5 + w;
1853                                        v->suggest.cy1 = 5;
1854                                        v->suggest.cy2 = 5 + h;
1855                                        v->suggest.pan_x = v->pan_x;
1856                                        v->suggest.pan_y = v->pan_y;
1857                                        v->suggest.shift_down = v->shift_down;
1858                                        v->suggest.shift_right = v->shift_right;
1859                                    }
1860                                }
1861                                draw();
1862                            } break;
1863                            case EV_REDRAW:
1864                            {
1865                                main_screen->AddDirty(ev.redraw.x1, ev.redraw.y1,
1866                                    ev.redraw.x2 + 1, ev.redraw.y2 + 1);
1867                            } break;
1868                            case EV_MESSAGE:
1869                            {
1870                                switch (ev.message.id)
1871                                {
1872                                    case RAISE_SFX:
1873                                    case LOWER_SFX:
1874                                    case RAISE_MUSIC:
1875                                    case LOWER_MUSIC:
1876                                    {
1877                                        if(ev.message.id == RAISE_SFX && sfx_volume != 127)
1878                                            sfx_volume = Min(127, sfx_volume + 16);
1879                                        if(ev.message.id == LOWER_SFX && sfx_volume != 0)
1880                                            sfx_volume = Max(sfx_volume - 16, 0);
1881                                        if(ev.message.id == RAISE_MUSIC && music_volume != 126)
1882                                        {
1883                                            music_volume = Min(music_volume + 16, 127);
1884                                            if(current_song && (sound_avail & MUSIC_INITIALIZED))
1885                                                current_song->set_volume(music_volume);
1886                                        }
1887
1888                                        if(ev.message.id == LOWER_MUSIC && music_volume != 0)
1889                                        {
1890                                            music_volume = Max(music_volume - 16, 0);
1891                                            if(current_song && (sound_avail & MUSIC_INITIALIZED))
1892                                                current_song->set_volume(music_volume);
1893                                        }
1894
1895                                        ((button *)ev.message.data)->push();
1896/*                                        volume_window->inm->redraw();
1897                                        draw_value(volume_window->m_surf, 2, 43,
1898                                                (volume_window->x2()-volume_window->x1()-1), 8, sfx_volume, 127);
1899                                        draw_value(volume_window->m_surf, 2, 94,
1900                                                (volume_window->x2()-volume_window->x1()-1), 8, music_volume, 127);
1901*/
1902                                        break;
1903                                    }
1904                                }
1905                            }
1906                        }
1907                    }
1908                } break;
1909            }
1910        }
1911    }
1912}
1913
1914
1915void net_send(int force = 0)
1916{
1917#if !defined __CELLOS_LV2__
1918  if((!(dev & EDIT_MODE)) || force)
1919  {
1920    if(demo_man.state == demo_manager::PLAYING)
1921    {
1922      base->input_state = INPUT_PROCESSING;
1923    } else
1924    {
1925
1926
1927
1928      if(!player_list->focus)
1929      {
1930    dprintf("Players have not been created\ncall create_players");
1931    exit(0);
1932      }
1933
1934
1935      view *p = player_list;
1936      for(; p; p = p->next)
1937        if(p->local_player())
1938      p->get_input();
1939
1940
1941      base->packet.write_uint8(SCMD_SYNC);
1942      base->packet.write_uint16(make_sync());
1943
1944      if(base->join_list)
1945      base->packet.write_uint8(SCMD_RELOAD);
1946
1947      //      printf("save tick %d, pk size=%d, rand_on=%d, sync=%d\n", current_level->tick_counter(),
1948      //         base->packet.packet_size(), rand_on, make_sync());
1949      send_local_request();
1950    }
1951  }
1952#endif
1953}
1954
1955void net_receive()
1956{
1957#if !defined __CELLOS_LV2__
1958  if(!(dev & EDIT_MODE) && current_level)
1959  {
1960    uint8_t buf[PACKET_MAX_SIZE + 1];
1961    int size;
1962
1963    if(demo_man.state == demo_manager::PLAYING)
1964    {
1965      if(!demo_man.get_packet(buf, size))
1966        size = 0;
1967      base->packet.packet_reset();
1968      base->mem_lock = 0;
1969    } else
1970    {
1971      size = get_inputs_from_server(buf);
1972      if(demo_man.state == demo_manager::RECORDING)
1973    demo_man.save_packet(buf, size);
1974    }
1975
1976    process_packet_commands(buf, size);
1977  }
1978#endif
1979}
1980
1981void Game::step()
1982{
1983  LSpace::Tmp.Clear();
1984  if(current_level)
1985  {
1986    current_level->unactivate_all();
1987    total_active = 0;
1988    for(view *f = first_view; f; f = f->next)
1989    {
1990      if(f->focus)
1991      {
1992    f->update_scroll();
1993    int w, h;
1994
1995    w=(f->cx2 - f->cx1 + 1);
1996    h=(f->cy2 - f->cy1 + 1);
1997        total_active += current_level->add_actives(f->xoff()-w / 4, f->yoff()-h / 4,
1998                         f->xoff()+w + w / 4, f->yoff()+h + h / 4);
1999      }
2000    }
2001  }
2002
2003  if(state == RUN_STATE)
2004  {
2005    if((dev & EDIT_MODE) || (main_net_cfg && (main_net_cfg->state == net_configuration::CLIENT ||
2006                         main_net_cfg->state == net_configuration::SERVER)))
2007      idle_ticks = 0;
2008
2009    if(demo_man.current_state()==demo_manager::NORMAL && idle_ticks > 420 && demo_start)
2010    {
2011      idle_ticks = 0;
2012      set_state(MENU_STATE);
2013    }
2014    else if(!(dev & EDIT_MODE))               // if edit mode, then don't step anything
2015    {
2016      if(key_down(JK_ESC))
2017      {
2018    set_state(MENU_STATE);
2019    set_key_down(JK_ESC, 0);
2020      }
2021      ambient_ramp = 0;
2022      view *v;
2023      for(v = first_view; v; v = v->next)
2024        v->update_scroll();
2025
2026      cache.prof_poll_start();
2027      current_level->tick();
2028      sbar.step();
2029    } else
2030      dev_scroll();
2031  } else if(state == JOY_CALB_STATE)
2032  {
2033    Event ev;
2034    joy_calb(ev);
2035  } else if(state == MENU_STATE)
2036    main_menu();
2037
2038  if((key_down('x') || key_down(JK_F4))
2039      && (key_down(JK_ALT_L) || key_down(JK_ALT_R))
2040      && confirm_quit())
2041    finished = true;
2042}
2043
2044extern void *current_demo;
2045
2046Game::~Game()
2047{
2048  current_demo = NULL;
2049  if(first_view == player_list) first_view = NULL;
2050  while(player_list)
2051  {
2052    view *p = player_list;
2053    game_object *o = p->focus;
2054    player_list = player_list->next;
2055    delete p;
2056    o->set_controller(NULL);
2057    if(current_level && o)
2058      current_level->delete_object(o);
2059    else delete o;
2060  }
2061
2062  if(current_level) { delete current_level; current_level = NULL; }
2063
2064  if(first_view != player_list)
2065  {
2066    while(player_list)
2067    {
2068      view *p = player_list;
2069      player_list = player_list->next;
2070      delete p;
2071    }
2072  }
2073
2074  while(first_view)
2075  {
2076    view *p = first_view;
2077    first_view = first_view->next;
2078    delete p;
2079  }
2080
2081  player_list = NULL;
2082
2083  if(old_view)
2084  {
2085    first_view = old_view;
2086    while(first_view)
2087    {
2088      view *p = first_view;
2089      first_view = first_view->next;
2090      delete p;
2091    }
2092  }
2093  old_view = NULL;
2094
2095  int i = 0;
2096  for(; i < total_objects; i++)
2097  {
2098    free(object_names[i]);
2099    delete figures[i];
2100  }
2101  free_pframes();
2102  delete pal;
2103  free(object_names);
2104  free(figures);
2105
2106  free(backtiles);
2107  free(foretiles);
2108  if(total_weapons)
2109    free(weapon_types);
2110
2111  config_cleanup();
2112  delete color_table;
2113  delete wm;
2114  delete game_font;
2115  delete big_font;
2116  delete console_font;
2117  if(total_help_screens)
2118    free(help_screens);
2119
2120  close_graphics();
2121  image_uninit();
2122}
2123
2124
2125
2126void Game::draw(int scene_mode)
2127{
2128    main_screen->AddDirty(0, 0, xres + 1, yres + 1);
2129
2130    main_screen->clear();
2131
2132    if(scene_mode)
2133    {
2134        char const *helpstr = "ARROW KEYS CHANGE TEXT SPEED";
2135        wm->font()->put_string(main_screen, main_screen->Size().x/2-(wm->font()->width()*strlen(helpstr))/2 + 1,
2136            main_screen->Size().y-wm->font()->height()-5 + 1, helpstr, wm->dark_color());
2137        wm->font()->put_string(main_screen, main_screen->Size().x/2-(wm->font()->width()*strlen(helpstr))/2,
2138            main_screen->Size().y-wm->font()->height()-5, helpstr, wm->bright_color());
2139    }
2140/*    else
2141    {
2142        char *helpstr="PRESS h FOR HELP";
2143        wm->font()->put_string(main_screen, main_screen->Size().x-wm->font()->width()*strlen(helpstr)-5,
2144            main_screen->Size().y-wm->font()->height()-5, helpstr);
2145    }*/
2146/*    int dc = cache.img(window_colors)->pixel(0, 2);
2147    int mc = cache.img(window_colors)->pixel(1, 2);
2148    int bc = cache.img(window_colors)->pixel(2, 2);
2149    main_screen->line(0, 0, main_screen->Size().x-1, 0, dc);
2150    main_screen->line(0, 0, 0, main_screen->Size().y-1, dc);
2151    main_screen->line(0, main_screen->Size().y-1, main_screen->Size().x-1, main_screen->Size().y-1, bc);
2152    main_screen->line(main_screen->Size().x-1, 0, main_screen->Size().x-1, main_screen->Size().y-1, bc); */
2153
2154    for(view *f = first_view; f; f = f->next)
2155        draw_map(f, 0);
2156
2157    sbar.redraw(main_screen);
2158}
2159
2160int external_print = 0;
2161
2162void start_sound(int argc, char **argv)
2163{
2164  sfx_volume = music_volume = 127;
2165
2166  for(int i = 1; i < argc; i++)
2167    if(!strcmp(argv[i], "-sfx_volume"))
2168    {
2169      i++;
2170      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2171        sfx_volume = atoi(argv[i]);
2172      else printf("Bad sound effects volume level, use 0..127\n");
2173    }
2174    else if(!strcmp(argv[i], "-music_volume"))
2175    {
2176      i++;
2177      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2178        music_volume = atoi(argv[i]);
2179      else printf("Bad music volume level, use 0..127\n");
2180    }
2181
2182  sound_avail = sound_init(argc, argv);
2183}
2184
2185void game_printer(char *st)
2186{
2187  if(dev_console && !external_print)
2188  {
2189    dev_console->put_string(st);
2190  }
2191  else fprintf(stderr, "%s", st);
2192}
2193
2194
2195void game_getter(char *st, int max)
2196{
2197  if(!max) return;
2198  max--;
2199  *st = 0;
2200  if(dev_console && !external_print)
2201  {
2202    dev_console->show();
2203    int t = 0;
2204    Event ev;
2205    do
2206    {
2207      get_event(ev);
2208      if(ev.type == EV_KEY)
2209      {
2210    if(ev.key == JK_BACKSPACE)
2211    {
2212      if(t)
2213      {
2214        dev_console->print_f("%c", ev.key);
2215        t--;
2216        st--;
2217        *st = 0;
2218        max++;
2219      }
2220    } else if(ev.key>=' ' && ev.key<='~')
2221    {
2222      dev_console->print_f("%c", ev.key);
2223      *st = ev.key;
2224      t++;
2225      max--;
2226      st++;
2227      *st = 0;
2228    }
2229      }
2230      wm->flush_screen();
2231    } while(ev.type != EV_KEY || ev.key != JK_ENTER);
2232    dprintf("\n");
2233  }
2234  else
2235  {
2236    if(fgets(st, max, stdin))
2237    {
2238      if(*st)
2239        st[strlen(st)-1]=0;
2240    }
2241  }
2242}
2243
2244
2245void show_startup()
2246{
2247    dprintf("Abuse version %s\n", PACKAGE_VERSION);
2248}
2249
2250char *get_line(int open_braces)
2251{
2252  char *line=(char *)malloc(1000);
2253  fgets(line, 1000, stdin);
2254
2255  char prev=' ';
2256  for(char *s = line; *s && (prev!=' ' || *s!=';'); s++)
2257  {
2258    prev=*s;
2259    if(*s=='(') open_braces++;
2260    else if(*s==')') open_braces--;
2261  }
2262  if(open_braces < 0)
2263    fprintf(stderr, "\nToo many)'s\n");
2264  else if(open_braces > 0)
2265  {
2266    char *s2 = get_line(open_braces);
2267    line=(char *)realloc(line, strlen(line)+strlen(s2)+1);
2268    strcat(line, s2);
2269    free(s2);
2270  }
2271  return line;
2272}
2273
2274void check_for_lisp(int argc, char **argv)
2275{
2276    for(int i = 1; i < argc; i++)
2277    {
2278        if(!strcmp(argv[i], "-lisp"))
2279        {
2280            Lisp::Init();
2281            char const *eof_char = "Ctrl-D";
2282            fprintf(stderr,
2283                    " CLIVE (C) 1995 Jonathan Clark, all rights reserved\n"
2284                    "   (C LISP interpreter and various extentions)\n"
2285                    "Type (%s) to exit\n", eof_char);
2286
2287            while(!feof(stdin))
2288            {
2289                fprintf(stderr, "Lisp> ");
2290                char *l = get_line(0);
2291                char const *s = l;
2292                while(*s)
2293                {
2294                    LObject *prog = LObject::Compile(s);
2295                    l_user_stack.push(prog);
2296                    while(*s==' ' || *s=='\t' || *s=='\r' || *s=='\n') s++;
2297                    prog->Eval()->Print();
2298                    l_user_stack.pop(1);
2299                }
2300                free(l);
2301            }
2302            fprintf(stderr, "End of input : bye\n");
2303            exit(0);
2304        }
2305    }
2306}
2307
2308
2309void music_check()
2310{
2311  if(sound_avail & MUSIC_INITIALIZED)
2312  {
2313    if(current_song && !current_song->playing())
2314    {
2315      current_song->play(music_volume);
2316      dprintf("song finished\n");
2317    }
2318    if(!current_song)
2319    {
2320
2321      current_song = new song("music/intro.hmi");
2322      current_song->play(music_volume);
2323
2324/*      if(DEFINEDP(symbol_function(l_next_song)))  // if user function installed, call it to load up next song
2325      {
2326    int sp = LSpace::Current;
2327    LSpace::Current = SPACE_PERM;
2328    ((LSymbol *)l_next_song)->EvalFunction(NULL);
2329    LSpace::Current = sp;
2330      } */
2331    }
2332  }
2333}
2334
2335void setup(int argc, char **argv);
2336
2337void share_end();
2338void show_end();
2339
2340void show_sell(int abortable);
2341
2342extern pmenu *dev_menu;
2343
2344void game_net_init(int argc, char **argv)
2345{
2346#if !defined __CELLOS_LV2__
2347  int nonet=!net_init(argc, argv);
2348  if(nonet)
2349    dprintf("No network driver, or network driver returned failure\n");
2350  else
2351  {
2352    set_file_opener(open_nfs_file);
2353    if(main_net_cfg && main_net_cfg->state == net_configuration::CLIENT)
2354    {
2355      if(set_file_server(net_server))
2356      start_running = 1;
2357      else
2358      {
2359                dprintf("Unable to attach to server, quitting\n");
2360                exit(0);
2361      }
2362    } else
2363    {
2364      int i;
2365      for(i = 1; i < argc - 1; i++)
2366      if(!strcmp(argv[i], "-fs"))
2367      if(!set_file_server(argv[i + 1]))
2368      dprintf("could not set default file server to %s\n", argv[i + 1]);
2369    }
2370  }
2371#endif
2372}
2373
2374int main(int argc, char *argv[])
2375{
2376    start_argc = argc;
2377    start_argv = argv;
2378
2379    for (int i = 0; i < argc; i++)
2380    {
2381        if (!strcmp(argv[i], "-cprint"))
2382            external_print = 1;
2383    }
2384
2385#if (defined(__APPLE__) && !defined(__MACH__))
2386    unsigned char km[16];
2387
2388    fprintf(stderr, "Mac Options: ");
2389    xres = 320; yres = 200;
2390    GetKeys((uint32_t*)&km);
2391    if ((km[ 0x3a >>3] >> (0x3a & 7)) &1 != 0)
2392    {
2393        dev|=EDIT_MODE;
2394        start_edit = 1;
2395        start_running = 1;
2396        disable_autolight = 1;
2397        fprintf(stderr, "Edit Mode...");
2398    }
2399    if ((km[ 0x3b >>3] >> (0x3b & 7)) &1 != 0)
2400    {
2401        PixMult = 1;
2402        fprintf(stderr, "Single Pixel...");
2403    }
2404    else
2405    {
2406        PixMult = 2;
2407        fprintf(stderr, "Double Pixel...");
2408    }
2409    if ((km[ 0x38 >>3] >> (0x38 & 7)) &1 != 0)
2410    {
2411        xres *= 2;  yres *= 2;
2412        fprintf(stderr, "Double Size...");
2413    }
2414    fprintf(stderr, "\n");
2415
2416    if (tcpip.installed())
2417        fprintf(stderr, "Using %s\n", tcpip.name());
2418#endif
2419
2420    set_dprinter(game_printer);
2421    set_dgetter(game_getter);
2422    set_no_space_handler(handle_no_space);
2423
2424    setup(argc, argv);
2425
2426    show_startup();
2427
2428    start_sound(argc, argv);
2429
2430    stat_man = new text_status_manager();
2431
2432#if !defined __CELLOS_LV2__
2433    // look to see if we are supposed to fetch the data elsewhere
2434    if (getenv("ABUSE_PATH"))
2435        set_filename_prefix(getenv("ABUSE_PATH"));
2436
2437    // look to see if we are supposed to save the data elsewhere
2438    if (getenv("ABUSE_SAVE_PATH"))
2439        set_save_filename_prefix(getenv("ABUSE_SAVE_PATH"));
2440#endif
2441
2442    jrand_init();
2443    jrand(); // so compiler doesn't complain
2444
2445    set_spec_main_file("abuse.spe");
2446    check_for_lisp(argc, argv);
2447
2448    do
2449    {
2450        if (main_net_cfg && !main_net_cfg->notify_reset())
2451        {
2452            sound_uninit();
2453            exit(0);
2454        }
2455
2456        game_net_init(argc, argv);
2457        Lisp::Init();
2458
2459        dev_init(argc, argv);
2460
2461        Game *g = new Game(argc, argv);
2462
2463        dev_cont = new dev_controll();
2464        dev_cont->load_stuff();
2465
2466        g->get_input(); // prime the net
2467
2468#if !defined __CELLOS_LV2__
2469        for (int i = 1; i + 1 < argc; i++)
2470        {
2471            if (!strcmp(argv[i], "-server"))
2472            {
2473                if (!become_server(argv[i + 1]))
2474                {
2475                    dprintf("unable to become a server\n");
2476                    exit(0);
2477                }
2478                break;
2479            }
2480        }
2481
2482        if (main_net_cfg)
2483            wait_min_players();
2484
2485        net_send(1);
2486        if (net_start())
2487        {
2488            g->step(); // process all the objects in the world
2489            g->calc_speed();
2490            g->update_screen(); // redraw the screen with any changes
2491        }
2492#endif
2493
2494        while (!g->done())
2495        {
2496            music_check();
2497
2498            if (req_end)
2499            {
2500                delete current_level; current_level = NULL;
2501
2502                show_end();
2503
2504                the_game->set_state(MENU_STATE);
2505                req_end = 0;
2506            }
2507
2508            if (demo_man.current_state() == demo_manager::NORMAL)
2509                net_receive();
2510
2511            // see if a request for a level load was made during the last tick
2512            if (req_name[0])
2513            {
2514                g->load_level(req_name);
2515                req_name[0] = 0;
2516                g->draw(g->state == SCENE_STATE);
2517            }
2518
2519            //if (demo_man.current_state() != demo_manager::PLAYING)
2520                g->get_input();
2521
2522            if (demo_man.current_state() == demo_manager::NORMAL)
2523                net_send();
2524            else
2525                demo_man.do_inputs();
2526
2527#if !defined __CELLOS_LV2__
2528            service_net_request();
2529#endif
2530
2531            // process all the objects in the world
2532            g->step();
2533#if !defined __CELLOS_LV2__
2534            server_check();
2535#endif
2536            g->calc_speed();
2537
2538            // see if a request for a level load was made during the last tick
2539            if (!req_name[0])
2540                g->update_screen(); // redraw the screen with any changes
2541        }
2542
2543#if !defined __CELLOS_LV2__
2544        net_uninit();
2545
2546        if (net_crcs)
2547            net_crcs->clean_up();
2548        delete net_crcs; net_crcs = NULL;
2549#endif
2550
2551        delete chat;
2552
2553        Timer tmp; tmp.WaitMs(500);
2554
2555        delete small_render; small_render = NULL;
2556
2557        if (current_song)
2558            current_song->stop();
2559        delete current_song; current_song = NULL;
2560
2561        cache.empty();
2562
2563        delete dev_console; dev_console = NULL;
2564        delete dev_menu; dev_menu = NULL;
2565        delete g; g = NULL;
2566        delete old_pal; old_pal = NULL;
2567
2568        compiled_uninit();
2569        delete_all_lights();
2570        free(white_light_initial);
2571
2572        for (int i = 0; i < TTINTS; i++)
2573            free(tints[i]);
2574
2575        dev_cleanup();
2576        delete dev_cont; dev_cont = NULL;
2577        delete stat_man; stat_man = new text_status_manager();
2578
2579        if (!(main_net_cfg && main_net_cfg->restart_state()))
2580        {
2581            LSymbol *end_msg = LSymbol::FindOrCreate("end_msg");
2582            if (DEFINEDP(end_msg->GetValue()))
2583                printf("%s\n", lstring_value(end_msg->GetValue()));
2584        }
2585
2586        Lisp::Uninit();
2587
2588#if !defined __CELLOS_LV2__
2589        base->packet.packet_reset();
2590#endif
2591    }
2592    while (main_net_cfg && main_net_cfg->restart_state());
2593
2594    delete stat_man;
2595    delete main_net_cfg; main_net_cfg = NULL;
2596
2597    set_filename_prefix(NULL);  // dealloc this mem if there was any
2598    set_save_filename_prefix(NULL);
2599
2600    sound_uninit();
2601
2602    return 0;
2603}
2604
Note: See TracBrowser for help on using the repository browser.