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

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

game: convert a few View members to vec2i.

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