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

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

game: prefix a few class members with m_ to avoid confusion.

File size: 63.9 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  if((!(dev & EDIT_MODE)) || force)
1817  {
1818    if(demo_man.state == demo_manager::PLAYING)
1819    {
1820      base->input_state = INPUT_PROCESSING;
1821    } else
1822    {
1823
1824
1825
1826      if(!player_list->m_focus)
1827      {
1828    dprintf("Players have not been created\ncall create_players");
1829    exit(0);
1830      }
1831
1832
1833      view *p = player_list;
1834      for(; p; p = p->next)
1835        if(p->local_player())
1836      p->get_input();
1837
1838
1839      base->packet.write_uint8(SCMD_SYNC);
1840      base->packet.write_uint16(make_sync());
1841
1842      if(base->join_list)
1843      base->packet.write_uint8(SCMD_RELOAD);
1844
1845      //      printf("save tick %d, pk size=%d, rand_on=%d, sync=%d\n", current_level->tick_counter(),
1846      //         base->packet.packet_size(), rand_on, make_sync());
1847      send_local_request();
1848    }
1849  }
1850}
1851
1852void net_receive()
1853{
1854  if(!(dev & EDIT_MODE) && current_level)
1855  {
1856    uint8_t buf[PACKET_MAX_SIZE + 1];
1857    int size;
1858
1859    if(demo_man.state == demo_manager::PLAYING)
1860    {
1861      if(!demo_man.get_packet(buf, size))
1862        size = 0;
1863      base->packet.packet_reset();
1864      base->mem_lock = 0;
1865    } else
1866    {
1867      size = get_inputs_from_server(buf);
1868      if(demo_man.state == demo_manager::RECORDING)
1869    demo_man.save_packet(buf, size);
1870    }
1871
1872    process_packet_commands(buf, size);
1873  }
1874}
1875
1876void Game::step()
1877{
1878  LSpace::Tmp.Clear();
1879  if(current_level)
1880  {
1881    current_level->unactivate_all();
1882    total_active = 0;
1883    for(view *f = first_view; f; f = f->next)
1884    {
1885      if(f->m_focus)
1886      {
1887    f->update_scroll();
1888    int w, h;
1889
1890    w = (f->m_bb.x - f->m_aa.x + 1);
1891    h = (f->m_bb.y - f->m_aa.y + 1);
1892        total_active += current_level->add_actives(f->xoff()-w / 4, f->yoff()-h / 4,
1893                         f->xoff()+w + w / 4, f->yoff()+h + h / 4);
1894      }
1895    }
1896  }
1897
1898  if(state == RUN_STATE)
1899  {
1900    if((dev & EDIT_MODE) || (main_net_cfg && (main_net_cfg->state == net_configuration::CLIENT ||
1901                         main_net_cfg->state == net_configuration::SERVER)))
1902      idle_ticks = 0;
1903
1904    if(demo_man.current_state()==demo_manager::NORMAL && idle_ticks > 420 && demo_start)
1905    {
1906      idle_ticks = 0;
1907      set_state(MENU_STATE);
1908    }
1909    else if(!(dev & EDIT_MODE))               // if edit mode, then don't step anything
1910    {
1911      if(key_down(JK_ESC))
1912      {
1913    set_state(MENU_STATE);
1914    set_key_down(JK_ESC, 0);
1915      }
1916      ambient_ramp = 0;
1917      view *v;
1918      for(v = first_view; v; v = v->next)
1919        v->update_scroll();
1920
1921      cache.prof_poll_start();
1922      current_level->tick();
1923      sbar.step();
1924    } else
1925      dev_scroll();
1926  } else if(state == JOY_CALB_STATE)
1927  {
1928    Event ev;
1929    joy_calb(ev);
1930  } else if(state == MENU_STATE)
1931    main_menu();
1932
1933  if((key_down('x') || key_down(JK_F4))
1934      && (key_down(JK_ALT_L) || key_down(JK_ALT_R))
1935      && confirm_quit())
1936    finished = true;
1937}
1938
1939extern void *current_demo;
1940
1941Game::~Game()
1942{
1943  current_demo = NULL;
1944  if(first_view == player_list) first_view = NULL;
1945  while(player_list)
1946  {
1947    view *p = player_list;
1948    game_object *o = p->m_focus;
1949    player_list = player_list->next;
1950    delete p;
1951    o->set_controller(NULL);
1952    if(current_level && o)
1953      current_level->delete_object(o);
1954    else delete o;
1955  }
1956
1957  if(current_level) { delete current_level; current_level = NULL; }
1958
1959  if(first_view != player_list)
1960  {
1961    while(player_list)
1962    {
1963      view *p = player_list;
1964      player_list = player_list->next;
1965      delete p;
1966    }
1967  }
1968
1969  while(first_view)
1970  {
1971    view *p = first_view;
1972    first_view = first_view->next;
1973    delete p;
1974  }
1975
1976  player_list = NULL;
1977
1978  if(old_view)
1979  {
1980    first_view = old_view;
1981    while(first_view)
1982    {
1983      view *p = first_view;
1984      first_view = first_view->next;
1985      delete p;
1986    }
1987  }
1988  old_view = NULL;
1989
1990  int i = 0;
1991  for(; i < total_objects; i++)
1992  {
1993    free(object_names[i]);
1994    delete figures[i];
1995  }
1996  free_pframes();
1997  delete pal;
1998  free(object_names);
1999  free(figures);
2000
2001  free(backtiles);
2002  free(foretiles);
2003  if(total_weapons)
2004    free(weapon_types);
2005
2006  config_cleanup();
2007  delete color_table;
2008  delete wm;
2009  delete game_font;
2010  delete big_font;
2011  delete console_font;
2012  if(total_help_screens)
2013    free(help_screens);
2014
2015  close_graphics();
2016  image_uninit();
2017}
2018
2019
2020
2021void Game::draw(int scene_mode)
2022{
2023    main_screen->AddDirty(vec2i(0), vec2i(xres, yres));
2024
2025    main_screen->clear();
2026
2027    if(scene_mode)
2028    {
2029        char const *helpstr = "ARROW KEYS CHANGE TEXT SPEED";
2030        vec2i span = wm->font()->Size() * vec2i(strlen(helpstr), 1);
2031        vec2i pos = (main_screen->Size() - span) / vec2i(2, 1);
2032        wm->font()->PutString(main_screen, pos + vec2i(1),
2033                              helpstr, wm->dark_color());
2034        wm->font()->PutString(main_screen, pos, helpstr, wm->bright_color());
2035    }
2036/*    else
2037    {
2038        char *helpstr="PRESS h FOR HELP";
2039        wm->font()->put_string(main_screen, main_screen->Size().x-wm->font()->width()*strlen(helpstr)-5,
2040            main_screen->Size().y-wm->font()->Size().y-5, helpstr);
2041    }*/
2042/*    int dc = cache.img(window_colors)->pixel(0, 2);
2043    int mc = cache.img(window_colors)->pixel(1, 2);
2044    int bc = cache.img(window_colors)->pixel(2, 2);
2045    main_screen->line(0, 0, main_screen->Size().x-1, 0, dc);
2046    main_screen->line(0, 0, 0, main_screen->Size().y-1, dc);
2047    main_screen->line(0, main_screen->Size().y-1, main_screen->Size().x-1, main_screen->Size().y-1, bc);
2048    main_screen->line(main_screen->Size().x-1, 0, main_screen->Size().x-1, main_screen->Size().y-1, bc); */
2049
2050    for(view *f = first_view; f; f = f->next)
2051        draw_map(f, 0);
2052
2053    sbar.redraw(main_screen);
2054}
2055
2056int external_print = 0;
2057
2058void start_sound(int argc, char **argv)
2059{
2060  sfx_volume = music_volume = 127;
2061
2062  for(int i = 1; i < argc; i++)
2063    if(!strcmp(argv[i], "-sfx_volume"))
2064    {
2065      i++;
2066      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2067        sfx_volume = atoi(argv[i]);
2068      else printf("Bad sound effects volume level, use 0..127\n");
2069    }
2070    else if(!strcmp(argv[i], "-music_volume"))
2071    {
2072      i++;
2073      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2074        music_volume = atoi(argv[i]);
2075      else printf("Bad music volume level, use 0..127\n");
2076    }
2077
2078  sound_avail = sound_init(argc, argv);
2079}
2080
2081void game_printer(char *st)
2082{
2083  if(dev_console && !external_print)
2084  {
2085    dev_console->put_string(st);
2086  }
2087  else fprintf(stderr, "%s", st);
2088}
2089
2090
2091void game_getter(char *st, int max)
2092{
2093  if(!max) return;
2094  max--;
2095  *st = 0;
2096  if(dev_console && !external_print)
2097  {
2098    dev_console->show();
2099    int t = 0;
2100    Event ev;
2101    do
2102    {
2103      get_event(ev);
2104      if(ev.type == EV_KEY)
2105      {
2106    if(ev.key == JK_BACKSPACE)
2107    {
2108      if(t)
2109      {
2110        dev_console->print_f("%c", ev.key);
2111        t--;
2112        st--;
2113        *st = 0;
2114        max++;
2115      }
2116    } else if(ev.key>=' ' && ev.key<='~')
2117    {
2118      dev_console->print_f("%c", ev.key);
2119      *st = ev.key;
2120      t++;
2121      max--;
2122      st++;
2123      *st = 0;
2124    }
2125      }
2126      wm->flush_screen();
2127    } while(ev.type != EV_KEY || ev.key != JK_ENTER);
2128    dprintf("\n");
2129  }
2130  else
2131  {
2132    if(fgets(st, max, stdin))
2133    {
2134      if(*st)
2135        st[strlen(st)-1]=0;
2136    }
2137  }
2138}
2139
2140
2141void show_startup()
2142{
2143    dprintf("Abuse version %s\n", PACKAGE_VERSION);
2144}
2145
2146char *get_line(int open_braces)
2147{
2148  char *line=(char *)malloc(1000);
2149  fgets(line, 1000, stdin);
2150
2151  char prev=' ';
2152  for(char *s = line; *s && (prev!=' ' || *s!=';'); s++)
2153  {
2154    prev=*s;
2155    if(*s=='(') open_braces++;
2156    else if(*s==')') open_braces--;
2157  }
2158  if(open_braces < 0)
2159    fprintf(stderr, "\nToo many)'s\n");
2160  else if(open_braces > 0)
2161  {
2162    char *s2 = get_line(open_braces);
2163    line=(char *)realloc(line, strlen(line)+strlen(s2)+1);
2164    strcat(line, s2);
2165    free(s2);
2166  }
2167  return line;
2168}
2169
2170void check_for_lisp(int argc, char **argv)
2171{
2172    for(int i = 1; i < argc; i++)
2173    {
2174        if(!strcmp(argv[i], "-lisp"))
2175        {
2176            Lisp::Init();
2177            char const *eof_char = "Ctrl-D";
2178            fprintf(stderr,
2179                    " CLIVE (C) 1995 Jonathan Clark, all rights reserved\n"
2180                    "   (C LISP interpreter and various extentions)\n"
2181                    "Type (%s) to exit\n", eof_char);
2182
2183            while(!feof(stdin))
2184            {
2185                fprintf(stderr, "Lisp> ");
2186                char *l = get_line(0);
2187                char const *s = l;
2188                while(*s)
2189                {
2190                    LObject *prog = LObject::Compile(s);
2191                    l_user_stack.push(prog);
2192                    while(*s==' ' || *s=='\t' || *s=='\r' || *s=='\n') s++;
2193                    prog->Eval()->Print();
2194                    l_user_stack.pop(1);
2195                }
2196                free(l);
2197            }
2198            fprintf(stderr, "End of input : bye\n");
2199            exit(0);
2200        }
2201    }
2202}
2203
2204
2205void music_check()
2206{
2207  if(sound_avail & MUSIC_INITIALIZED)
2208  {
2209    if(current_song && !current_song->playing())
2210    {
2211      current_song->play(music_volume);
2212      dprintf("song finished\n");
2213    }
2214    if(!current_song)
2215    {
2216
2217      current_song = new song("music/intro.hmi");
2218      current_song->play(music_volume);
2219
2220/*      if(DEFINEDP(symbol_function(l_next_song)))  // if user function installed, call it to load up next song
2221      {
2222    int sp = LSpace::Current;
2223    LSpace::Current = SPACE_PERM;
2224    ((LSymbol *)l_next_song)->EvalFunction(NULL);
2225    LSpace::Current = sp;
2226      } */
2227    }
2228  }
2229}
2230
2231void setup(int argc, char **argv);
2232
2233void share_end();
2234void show_end();
2235
2236void show_sell(int abortable);
2237
2238extern pmenu *dev_menu;
2239
2240void game_net_init(int argc, char **argv)
2241{
2242  int nonet=!net_init(argc, argv);
2243  if(nonet)
2244    dprintf("No network driver, or network driver returned failure\n");
2245  else
2246  {
2247    set_file_opener(open_nfs_file);
2248    if(main_net_cfg && main_net_cfg->state == net_configuration::CLIENT)
2249    {
2250      if(set_file_server(net_server))
2251      start_running = 1;
2252      else
2253      {
2254                dprintf("Unable to attach to server, quitting\n");
2255                exit(0);
2256      }
2257    } else
2258    {
2259      int i;
2260      for(i = 1; i < argc - 1; i++)
2261      if(!strcmp(argv[i], "-fs"))
2262      if(!set_file_server(argv[i + 1]))
2263      dprintf("could not set default file server to %s\n", argv[i + 1]);
2264    }
2265  }
2266}
2267
2268int main(int argc, char *argv[])
2269{
2270    start_argc = argc;
2271    start_argv = argv;
2272
2273    for (int i = 0; i < argc; i++)
2274    {
2275        if (!strcmp(argv[i], "-cprint"))
2276            external_print = 1;
2277    }
2278
2279#if (defined(__APPLE__) && !defined(__MACH__))
2280    unsigned char km[16];
2281
2282    fprintf(stderr, "Mac Options: ");
2283    xres = 320; yres = 200;
2284    GetKeys((uint32_t*)&km);
2285    if ((km[ 0x3a >>3] >> (0x3a & 7)) &1 != 0)
2286    {
2287        dev|=EDIT_MODE;
2288        start_edit = 1;
2289        start_running = 1;
2290        disable_autolight = 1;
2291        fprintf(stderr, "Edit Mode...");
2292    }
2293    if ((km[ 0x3b >>3] >> (0x3b & 7)) &1 != 0)
2294    {
2295        PixMult = 1;
2296        fprintf(stderr, "Single Pixel...");
2297    }
2298    else
2299    {
2300        PixMult = 2;
2301        fprintf(stderr, "Double Pixel...");
2302    }
2303    if ((km[ 0x38 >>3] >> (0x38 & 7)) &1 != 0)
2304    {
2305        xres *= 2;  yres *= 2;
2306        fprintf(stderr, "Double Size...");
2307    }
2308    fprintf(stderr, "\n");
2309
2310    if (tcpip.installed())
2311        fprintf(stderr, "Using %s\n", tcpip.name());
2312#endif
2313
2314    set_dprinter(game_printer);
2315    set_dgetter(game_getter);
2316    set_no_space_handler(handle_no_space);
2317
2318    setup(argc, argv);
2319
2320    show_startup();
2321
2322    start_sound(argc, argv);
2323
2324    stat_man = new text_status_manager();
2325
2326#if !defined __CELLOS_LV2__
2327    // look to see if we are supposed to fetch the data elsewhere
2328    if (getenv("ABUSE_PATH"))
2329        set_filename_prefix(getenv("ABUSE_PATH"));
2330
2331    // look to see if we are supposed to save the data elsewhere
2332    if (getenv("ABUSE_SAVE_PATH"))
2333        set_save_filename_prefix(getenv("ABUSE_SAVE_PATH"));
2334#endif
2335
2336    jrand_init();
2337    jrand(); // so compiler doesn't complain
2338
2339    set_spec_main_file("abuse.spe");
2340    check_for_lisp(argc, argv);
2341
2342    do
2343    {
2344        if (main_net_cfg && !main_net_cfg->notify_reset())
2345        {
2346            sound_uninit();
2347            exit(0);
2348        }
2349
2350        game_net_init(argc, argv);
2351        Lisp::Init();
2352
2353        dev_init(argc, argv);
2354
2355        Game *g = new Game(argc, argv);
2356
2357        dev_cont = new dev_controll();
2358        dev_cont->load_stuff();
2359
2360        g->get_input(); // prime the net
2361
2362        for (int i = 1; i + 1 < argc; i++)
2363        {
2364            if (!strcmp(argv[i], "-server"))
2365            {
2366                if (!become_server(argv[i + 1]))
2367                {
2368                    dprintf("unable to become a server\n");
2369                    exit(0);
2370                }
2371                break;
2372            }
2373        }
2374
2375        if (main_net_cfg)
2376            wait_min_players();
2377
2378        net_send(1);
2379        if (net_start())
2380        {
2381            g->step(); // process all the objects in the world
2382            g->calc_speed();
2383            g->update_screen(); // redraw the screen with any changes
2384        }
2385
2386        while (!g->done())
2387        {
2388            music_check();
2389
2390            if (req_end)
2391            {
2392                delete current_level; current_level = NULL;
2393
2394                show_end();
2395
2396                the_game->set_state(MENU_STATE);
2397                req_end = 0;
2398            }
2399
2400            if (demo_man.current_state() == demo_manager::NORMAL)
2401                net_receive();
2402
2403            // see if a request for a level load was made during the last tick
2404            if (req_name[0])
2405            {
2406                g->load_level(req_name);
2407                req_name[0] = 0;
2408                g->draw(g->state == SCENE_STATE);
2409            }
2410
2411            //if (demo_man.current_state() != demo_manager::PLAYING)
2412                g->get_input();
2413
2414            if (demo_man.current_state() == demo_manager::NORMAL)
2415                net_send();
2416            else
2417                demo_man.do_inputs();
2418
2419            service_net_request();
2420
2421            // process all the objects in the world
2422            g->step();
2423            server_check();
2424            g->calc_speed();
2425
2426            // see if a request for a level load was made during the last tick
2427            if (!req_name[0])
2428                g->update_screen(); // redraw the screen with any changes
2429        }
2430
2431        net_uninit();
2432
2433        if (net_crcs)
2434            net_crcs->clean_up();
2435        delete net_crcs; net_crcs = NULL;
2436
2437        delete chat;
2438
2439        Timer tmp; tmp.WaitMs(500);
2440
2441        delete small_render; small_render = NULL;
2442
2443        if (current_song)
2444            current_song->stop();
2445        delete current_song; current_song = NULL;
2446
2447        cache.empty();
2448
2449        delete dev_console; dev_console = NULL;
2450        delete dev_menu; dev_menu = NULL;
2451        delete g; g = NULL;
2452        delete old_pal; old_pal = NULL;
2453
2454        compiled_uninit();
2455        delete_all_lights();
2456        free(white_light_initial);
2457
2458        for (int i = 0; i < TTINTS; i++)
2459            free(tints[i]);
2460
2461        dev_cleanup();
2462        delete dev_cont; dev_cont = NULL;
2463        delete stat_man; stat_man = new text_status_manager();
2464
2465        if (!(main_net_cfg && main_net_cfg->restart_state()))
2466        {
2467            LSymbol *end_msg = LSymbol::FindOrCreate("end_msg");
2468            if (DEFINEDP(end_msg->GetValue()))
2469                printf("%s\n", lstring_value(end_msg->GetValue()));
2470        }
2471
2472        Lisp::Uninit();
2473
2474        base->packet.packet_reset();
2475    }
2476    while (main_net_cfg && main_net_cfg->restart_state());
2477
2478    delete stat_man;
2479    delete main_net_cfg; main_net_cfg = NULL;
2480
2481    set_filename_prefix(NULL);  // dealloc this mem if there was any
2482    set_save_filename_prefix(NULL);
2483
2484    sound_uninit();
2485
2486    return 0;
2487}
2488
Note: See TracBrowser for help on using the repository browser.