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

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

build: add a --disable-network compilation flag and get rid of most of
the CELLOS_LV2 ifdefs.

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