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

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

game: convert a few integer pairs to vec2i variables.

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