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

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

ps3: crash fix in remains of the network play.

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