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

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

imlib: make JCFont use vec2i classes.

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