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

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

game: refactor the GetFg? methods to use vec2i.

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()->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::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()->height()+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()->put_string(main_screen, 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->put_string(main_screen, first_view->cx1, first_view->cy1, str);
1450
1451    sprintf(str, "%d", total_active);
1452    console_font->put_string(main_screen, 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        wm->font()->put_string(main_screen, main_screen->Size().x/2-(wm->font()->width()*strlen(helpstr))/2 + 1,
2055            main_screen->Size().y-wm->font()->height()-5 + 1, helpstr, wm->dark_color());
2056        wm->font()->put_string(main_screen, main_screen->Size().x/2-(wm->font()->width()*strlen(helpstr))/2,
2057            main_screen->Size().y-wm->font()->height()-5, helpstr, wm->bright_color());
2058    }
2059/*    else
2060    {
2061        char *helpstr="PRESS h FOR HELP";
2062        wm->font()->put_string(main_screen, main_screen->Size().x-wm->font()->width()*strlen(helpstr)-5,
2063            main_screen->Size().y-wm->font()->height()-5, helpstr);
2064    }*/
2065/*    int dc = cache.img(window_colors)->pixel(0, 2);
2066    int mc = cache.img(window_colors)->pixel(1, 2);
2067    int bc = cache.img(window_colors)->pixel(2, 2);
2068    main_screen->line(0, 0, main_screen->Size().x-1, 0, dc);
2069    main_screen->line(0, 0, 0, main_screen->Size().y-1, dc);
2070    main_screen->line(0, main_screen->Size().y-1, main_screen->Size().x-1, main_screen->Size().y-1, bc);
2071    main_screen->line(main_screen->Size().x-1, 0, main_screen->Size().x-1, main_screen->Size().y-1, bc); */
2072
2073    for(view *f = first_view; f; f = f->next)
2074        draw_map(f, 0);
2075
2076    sbar.redraw(main_screen);
2077}
2078
2079int external_print = 0;
2080
2081void start_sound(int argc, char **argv)
2082{
2083  sfx_volume = music_volume = 127;
2084
2085  for(int i = 1; i < argc; i++)
2086    if(!strcmp(argv[i], "-sfx_volume"))
2087    {
2088      i++;
2089      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2090        sfx_volume = atoi(argv[i]);
2091      else printf("Bad sound effects volume level, use 0..127\n");
2092    }
2093    else if(!strcmp(argv[i], "-music_volume"))
2094    {
2095      i++;
2096      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2097        music_volume = atoi(argv[i]);
2098      else printf("Bad music volume level, use 0..127\n");
2099    }
2100
2101  sound_avail = sound_init(argc, argv);
2102}
2103
2104void game_printer(char *st)
2105{
2106  if(dev_console && !external_print)
2107  {
2108    dev_console->put_string(st);
2109  }
2110  else fprintf(stderr, "%s", st);
2111}
2112
2113
2114void game_getter(char *st, int max)
2115{
2116  if(!max) return;
2117  max--;
2118  *st = 0;
2119  if(dev_console && !external_print)
2120  {
2121    dev_console->show();
2122    int t = 0;
2123    Event ev;
2124    do
2125    {
2126      get_event(ev);
2127      if(ev.type == EV_KEY)
2128      {
2129    if(ev.key == JK_BACKSPACE)
2130    {
2131      if(t)
2132      {
2133        dev_console->print_f("%c", ev.key);
2134        t--;
2135        st--;
2136        *st = 0;
2137        max++;
2138      }
2139    } else if(ev.key>=' ' && ev.key<='~')
2140    {
2141      dev_console->print_f("%c", ev.key);
2142      *st = ev.key;
2143      t++;
2144      max--;
2145      st++;
2146      *st = 0;
2147    }
2148      }
2149      wm->flush_screen();
2150    } while(ev.type != EV_KEY || ev.key != JK_ENTER);
2151    dprintf("\n");
2152  }
2153  else
2154  {
2155    if(fgets(st, max, stdin))
2156    {
2157      if(*st)
2158        st[strlen(st)-1]=0;
2159    }
2160  }
2161}
2162
2163
2164void show_startup()
2165{
2166    dprintf("Abuse version %s\n", PACKAGE_VERSION);
2167}
2168
2169char *get_line(int open_braces)
2170{
2171  char *line=(char *)malloc(1000);
2172  fgets(line, 1000, stdin);
2173
2174  char prev=' ';
2175  for(char *s = line; *s && (prev!=' ' || *s!=';'); s++)
2176  {
2177    prev=*s;
2178    if(*s=='(') open_braces++;
2179    else if(*s==')') open_braces--;
2180  }
2181  if(open_braces < 0)
2182    fprintf(stderr, "\nToo many)'s\n");
2183  else if(open_braces > 0)
2184  {
2185    char *s2 = get_line(open_braces);
2186    line=(char *)realloc(line, strlen(line)+strlen(s2)+1);
2187    strcat(line, s2);
2188    free(s2);
2189  }
2190  return line;
2191}
2192
2193void check_for_lisp(int argc, char **argv)
2194{
2195    for(int i = 1; i < argc; i++)
2196    {
2197        if(!strcmp(argv[i], "-lisp"))
2198        {
2199            Lisp::Init();
2200            char const *eof_char = "Ctrl-D";
2201            fprintf(stderr,
2202                    " CLIVE (C) 1995 Jonathan Clark, all rights reserved\n"
2203                    "   (C LISP interpreter and various extentions)\n"
2204                    "Type (%s) to exit\n", eof_char);
2205
2206            while(!feof(stdin))
2207            {
2208                fprintf(stderr, "Lisp> ");
2209                char *l = get_line(0);
2210                char const *s = l;
2211                while(*s)
2212                {
2213                    LObject *prog = LObject::Compile(s);
2214                    l_user_stack.push(prog);
2215                    while(*s==' ' || *s=='\t' || *s=='\r' || *s=='\n') s++;
2216                    prog->Eval()->Print();
2217                    l_user_stack.pop(1);
2218                }
2219                free(l);
2220            }
2221            fprintf(stderr, "End of input : bye\n");
2222            exit(0);
2223        }
2224    }
2225}
2226
2227
2228void music_check()
2229{
2230  if(sound_avail & MUSIC_INITIALIZED)
2231  {
2232    if(current_song && !current_song->playing())
2233    {
2234      current_song->play(music_volume);
2235      dprintf("song finished\n");
2236    }
2237    if(!current_song)
2238    {
2239
2240      current_song = new song("music/intro.hmi");
2241      current_song->play(music_volume);
2242
2243/*      if(DEFINEDP(symbol_function(l_next_song)))  // if user function installed, call it to load up next song
2244      {
2245    int sp = LSpace::Current;
2246    LSpace::Current = SPACE_PERM;
2247    ((LSymbol *)l_next_song)->EvalFunction(NULL);
2248    LSpace::Current = sp;
2249      } */
2250    }
2251  }
2252}
2253
2254void setup(int argc, char **argv);
2255
2256void share_end();
2257void show_end();
2258
2259void show_sell(int abortable);
2260
2261extern pmenu *dev_menu;
2262
2263void game_net_init(int argc, char **argv)
2264{
2265  int nonet=!net_init(argc, argv);
2266  if(nonet)
2267    dprintf("No network driver, or network driver returned failure\n");
2268  else
2269  {
2270    set_file_opener(open_nfs_file);
2271    if(main_net_cfg && main_net_cfg->state == net_configuration::CLIENT)
2272    {
2273      if(set_file_server(net_server))
2274      start_running = 1;
2275      else
2276      {
2277                dprintf("Unable to attach to server, quitting\n");
2278                exit(0);
2279      }
2280    } else
2281    {
2282      int i;
2283      for(i = 1; i < argc - 1; i++)
2284      if(!strcmp(argv[i], "-fs"))
2285      if(!set_file_server(argv[i + 1]))
2286      dprintf("could not set default file server to %s\n", argv[i + 1]);
2287    }
2288  }
2289}
2290
2291int main(int argc, char *argv[])
2292{
2293    start_argc = argc;
2294    start_argv = argv;
2295
2296    for (int i = 0; i < argc; i++)
2297    {
2298        if (!strcmp(argv[i], "-cprint"))
2299            external_print = 1;
2300    }
2301
2302#if (defined(__APPLE__) && !defined(__MACH__))
2303    unsigned char km[16];
2304
2305    fprintf(stderr, "Mac Options: ");
2306    xres = 320; yres = 200;
2307    GetKeys((uint32_t*)&km);
2308    if ((km[ 0x3a >>3] >> (0x3a & 7)) &1 != 0)
2309    {
2310        dev|=EDIT_MODE;
2311        start_edit = 1;
2312        start_running = 1;
2313        disable_autolight = 1;
2314        fprintf(stderr, "Edit Mode...");
2315    }
2316    if ((km[ 0x3b >>3] >> (0x3b & 7)) &1 != 0)
2317    {
2318        PixMult = 1;
2319        fprintf(stderr, "Single Pixel...");
2320    }
2321    else
2322    {
2323        PixMult = 2;
2324        fprintf(stderr, "Double Pixel...");
2325    }
2326    if ((km[ 0x38 >>3] >> (0x38 & 7)) &1 != 0)
2327    {
2328        xres *= 2;  yres *= 2;
2329        fprintf(stderr, "Double Size...");
2330    }
2331    fprintf(stderr, "\n");
2332
2333    if (tcpip.installed())
2334        fprintf(stderr, "Using %s\n", tcpip.name());
2335#endif
2336
2337    set_dprinter(game_printer);
2338    set_dgetter(game_getter);
2339    set_no_space_handler(handle_no_space);
2340
2341    setup(argc, argv);
2342
2343    show_startup();
2344
2345    start_sound(argc, argv);
2346
2347    stat_man = new text_status_manager();
2348
2349#if !defined __CELLOS_LV2__
2350    // look to see if we are supposed to fetch the data elsewhere
2351    if (getenv("ABUSE_PATH"))
2352        set_filename_prefix(getenv("ABUSE_PATH"));
2353
2354    // look to see if we are supposed to save the data elsewhere
2355    if (getenv("ABUSE_SAVE_PATH"))
2356        set_save_filename_prefix(getenv("ABUSE_SAVE_PATH"));
2357#endif
2358
2359    jrand_init();
2360    jrand(); // so compiler doesn't complain
2361
2362    set_spec_main_file("abuse.spe");
2363    check_for_lisp(argc, argv);
2364
2365    do
2366    {
2367        if (main_net_cfg && !main_net_cfg->notify_reset())
2368        {
2369            sound_uninit();
2370            exit(0);
2371        }
2372
2373        game_net_init(argc, argv);
2374        Lisp::Init();
2375
2376        dev_init(argc, argv);
2377
2378        Game *g = new Game(argc, argv);
2379
2380        dev_cont = new dev_controll();
2381        dev_cont->load_stuff();
2382
2383        g->get_input(); // prime the net
2384
2385        for (int i = 1; i + 1 < argc; i++)
2386        {
2387            if (!strcmp(argv[i], "-server"))
2388            {
2389                if (!become_server(argv[i + 1]))
2390                {
2391                    dprintf("unable to become a server\n");
2392                    exit(0);
2393                }
2394                break;
2395            }
2396        }
2397
2398        if (main_net_cfg)
2399            wait_min_players();
2400
2401        net_send(1);
2402        if (net_start())
2403        {
2404            g->step(); // process all the objects in the world
2405            g->calc_speed();
2406            g->update_screen(); // redraw the screen with any changes
2407        }
2408
2409        while (!g->done())
2410        {
2411            music_check();
2412
2413            if (req_end)
2414            {
2415                delete current_level; current_level = NULL;
2416
2417                show_end();
2418
2419                the_game->set_state(MENU_STATE);
2420                req_end = 0;
2421            }
2422
2423            if (demo_man.current_state() == demo_manager::NORMAL)
2424                net_receive();
2425
2426            // see if a request for a level load was made during the last tick
2427            if (req_name[0])
2428            {
2429                g->load_level(req_name);
2430                req_name[0] = 0;
2431                g->draw(g->state == SCENE_STATE);
2432            }
2433
2434            //if (demo_man.current_state() != demo_manager::PLAYING)
2435                g->get_input();
2436
2437            if (demo_man.current_state() == demo_manager::NORMAL)
2438                net_send();
2439            else
2440                demo_man.do_inputs();
2441
2442            service_net_request();
2443
2444            // process all the objects in the world
2445            g->step();
2446            server_check();
2447            g->calc_speed();
2448
2449            // see if a request for a level load was made during the last tick
2450            if (!req_name[0])
2451                g->update_screen(); // redraw the screen with any changes
2452        }
2453
2454        net_uninit();
2455
2456        if (net_crcs)
2457            net_crcs->clean_up();
2458        delete net_crcs; net_crcs = NULL;
2459
2460        delete chat;
2461
2462        Timer tmp; tmp.WaitMs(500);
2463
2464        delete small_render; small_render = NULL;
2465
2466        if (current_song)
2467            current_song->stop();
2468        delete current_song; current_song = NULL;
2469
2470        cache.empty();
2471
2472        delete dev_console; dev_console = NULL;
2473        delete dev_menu; dev_menu = NULL;
2474        delete g; g = NULL;
2475        delete old_pal; old_pal = NULL;
2476
2477        compiled_uninit();
2478        delete_all_lights();
2479        free(white_light_initial);
2480
2481        for (int i = 0; i < TTINTS; i++)
2482            free(tints[i]);
2483
2484        dev_cleanup();
2485        delete dev_cont; dev_cont = NULL;
2486        delete stat_man; stat_man = new text_status_manager();
2487
2488        if (!(main_net_cfg && main_net_cfg->restart_state()))
2489        {
2490            LSymbol *end_msg = LSymbol::FindOrCreate("end_msg");
2491            if (DEFINEDP(end_msg->GetValue()))
2492                printf("%s\n", lstring_value(end_msg->GetValue()));
2493        }
2494
2495        Lisp::Uninit();
2496
2497        base->packet.packet_reset();
2498    }
2499    while (main_net_cfg && main_net_cfg->restart_state());
2500
2501    delete stat_man;
2502    delete main_net_cfg; main_net_cfg = NULL;
2503
2504    set_filename_prefix(NULL);  // dealloc this mem if there was any
2505    set_save_filename_prefix(NULL);
2506
2507    sound_uninit();
2508
2509    return 0;
2510}
2511
Note: See TracBrowser for help on using the repository browser.