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

Last change on this file since 518 was 518, checked in by Sam Hocevar, 10 years ago

imlib: refactor dirty_rect clipping coordiantes so that the upper
bound is no longer inclusive. It will make things easier in the future.

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