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

Last change on this file since 533 was 533, checked in by Sam Hocevar, 12 years ago

imlib: rename trans_image to TImage. The code is now clean enough.

File size: 67.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 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, TImage *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->PutImage(screen, vec2i((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
936    for(x = x1, draw_x = xo; x <= x2; x++, draw_x += xinc, cl++)
937    {
938      if(x < fg_w && y < fg_h)
939      {
940        if(above_tile(*cl))
941        rescan = 1;
942        else
943        {
944          int fort_num = fgvalue(*cl);
945          if(fort_num != BLACK)
946          {
947            get_fg(fort_num)->im->PutImage(screen, vec2i(draw_x, draw_y));
948
949        if(!(dev & EDIT_MODE))
950            *cl|=0x8000;      // mark as has - been - seen
951          }
952        }
953      }
954    }
955      }
956    }
957  }
958
959  int32_t ro = rand_on;
960  if(dev & DRAW_PEOPLE_LAYER)
961  {
962    if(interpolate)
963      current_level->interpolate_draw_objects(v);
964    else
965      current_level->draw_objects(v);
966  }
967
968//  if(!(dev & EDIT_MODE))
969//    server_check();
970
971  if(!(dev & MAP_MODE))
972  {
973
974    draw_panims(v);
975
976    if(dev & DRAW_FG_LAYER && rescan)
977    {
978      for(y = y1, draw_y = yo; y <= y2; y++, draw_y += yinc)
979      {
980    uint16_t *cl = current_level->get_fgline(y)+x1;
981    for(x = x1, draw_x = xo; x <= x2; x++, draw_x += xinc, cl++)
982    {
983      if(above_tile(*cl))
984      {
985        int fort_num = fgvalue(*cl);
986        if(fort_num != BLACK)
987        {
988          if(dev & DRAW_BG_LAYER)
989          get_fg(fort_num)->im->PutImage(screen, vec2i(draw_x, draw_y));
990          else
991          get_fg(fort_num)->im->PutFilled(screen, vec2i(draw_x, draw_y), 0);
992
993          if(!(dev & EDIT_MODE))
994          current_level->mark_seen(x, y);
995          else
996          {
997        screen->line(draw_x, draw_y, draw_x + xinc, draw_y + yinc, wm->bright_color());
998        screen->line(draw_x + xinc, draw_y, draw_x, draw_y + yinc, wm->bright_color());
999          }
1000        }
1001      }
1002    }
1003      }
1004    }
1005
1006
1007    if(dev & DRAW_FG_BOUND_LAYER)
1008    {
1009      int b = wm->bright_color();
1010      int fg_h = current_level->foreground_height(), fg_w = current_level->foreground_width();
1011
1012      for(y = y1, draw_y = yo; y <= y2; y++, draw_y += yinc)
1013      {
1014    uint16_t *cl;
1015    if(y < fg_h)
1016      cl = current_level->get_fgline(y)+x1;
1017    else cl = NULL;
1018    for(x = x1, draw_x = xo; x <= x2; x++, draw_x += xinc, cl++)
1019    {
1020      if(x < fg_w && y < fg_h)
1021      {
1022        int fort_num = fgvalue(*cl);
1023        if(fort_num != BLACK)
1024        {
1025          point_list *p = get_fg(fort_num)->points;
1026          uint8_t *d = p->data;
1027          if(p->tot)
1028          {
1029        for(int i = 1; i < p->tot; i++)
1030        {
1031          d += 2;
1032          screen->line(draw_x+*(d - 2), draw_y+*(d - 1), draw_x+*d, draw_y+*(d + 1), b);
1033        }
1034        screen->line(draw_x+*d, draw_y+*(d - 1), draw_x + p->data[0], draw_y + p->data[1], b);
1035          }
1036        }
1037      }
1038    }
1039      }
1040    }
1041
1042//    if(!(dev & EDIT_MODE))
1043//      server_check();
1044
1045    if(dev & DRAW_HELP_LAYER)
1046    {
1047      if(help_text_frames >= 0)
1048      {
1049    int color;
1050
1051    if(help_text_frames < 10)
1052        color = 2;
1053    else
1054        color = 2+(help_text_frames - 10);
1055
1056    int x1 = v->cx1, y1 = v->cy1, x2 = v->cx2, y2 = v->cy1 + wm->font()->height()+10;
1057
1058    remap_area(screen, x1, y1, x2, y2, white_light + 40 * 256);
1059    screen->bar(x1, y1, x2, y1, color);
1060    screen->bar(x1, y2, x2, y2, color);
1061
1062    wm->font()->put_string(screen, x1 + 5, y1 + 5,
1063                   help_text, color);
1064    if(color > 30)
1065        help_text_frames = -1;
1066    else help_text_frames++;
1067
1068      }
1069    }
1070
1071    if(dev_cont)
1072    dev_cont->dev_draw(v);
1073    if(cache.in_use())
1074    cache.img(vmm_image)->put_image(screen, v->cx1, v->cy2 - cache.img(vmm_image)->Size().y+1);
1075
1076    if(dev & DRAW_LIGHTS)
1077    {
1078      if(small_render)
1079      {
1080    double_light_screen(screen, xoff, yoff, white_light, v->ambient, old_screen, old_cx1, old_cy1);
1081
1082    v->cx1 = old_cx1;
1083    v->cy1 = old_cy1;
1084    v->cx2 = old_cx2;
1085    v->cy2 = old_cy2;
1086    screen = old_screen;
1087      } else
1088      {
1089    screen->dirt_on();
1090    if(xres * yres <= 64000)
1091          light_screen(screen, xoff, yoff, white_light, v->ambient);
1092    else light_screen(screen, xoff, yoff, white_light, 63);            // no lighting for hi - rez
1093      }
1094
1095    } else
1096      screen->dirt_on();
1097
1098
1099
1100  }  else
1101    screen->dirt_on();
1102
1103  rand_on = ro;                // restore random start in case in draw funs moved it
1104                               // ... not every machine will draw the same thing
1105
1106  post_render();
1107
1108  screen->SetClip(cx1, cy1, cx2 + 1, cy2 + 1);
1109
1110
1111
1112
1113  if(playing_state(state))        // draw stuff outside the clipping region
1114    v->draw_character_damage();
1115
1116  if(profiling())
1117    profile_update();
1118
1119  sbar.draw_update();
1120}
1121
1122void Game::put_fg(int x, int y, int type)
1123{
1124  if(current_level->get_fg(x, y)!=type)
1125  {
1126    current_level->put_fg(x, y, type);
1127    for(view *f = first_view; f; f = f->next)
1128      if(f->drawable())
1129        draw_map(f);
1130  }
1131}
1132
1133void Game::put_bg(int x, int y, int type)
1134{
1135  if(current_level->get_bg(x, y)!=type)
1136  {
1137    current_level->put_bg(x, y, type);
1138    for(view *f = first_view; f; f = f->next)
1139      if(f->drawable())
1140        draw_map(f);
1141  }
1142}
1143
1144int Game::in_area(event &ev, int x1, int y1, int x2, int y2)
1145{
1146  return (last_demo_mx >= x1 && last_demo_mx <= x2 &&
1147      last_demo_my >= y1 && last_demo_my <= y2);
1148}
1149
1150void Game::request_level_load(char *name)
1151{
1152  strcpy(req_name, name);
1153}
1154
1155extern int start_doubled;
1156
1157void fade_in(image *im, int steps)
1158{
1159  palette *old_pal = pal->copy();
1160  int i;
1161  if(im)
1162  {
1163    screen->clear();
1164    im->put_image(screen, (xres + 1)/2 - im->Size().x/2, (yres + 1)/2 - im->Size().y/2);
1165  }
1166
1167  for(i = 0; i < steps; i++)
1168  {
1169    uint8_t *sl1=(uint8_t *)pal->addr();
1170    uint8_t *sl2=(uint8_t *)old_pal->addr();
1171    int j;
1172    int v=(i + 1)*256 / steps;
1173    for(j = 0; j < 256; j++)
1174    {
1175      *(sl1)=((int)*(sl2))*v / 256;  sl1++; sl2++;
1176      *(sl1)=((int)*(sl2))*v / 256;  sl1++; sl2++;
1177      *(sl1)=((int)*(sl2))*v / 256;  sl1++; sl2++;
1178    }
1179    pal->load();
1180    wm->flush_screen();
1181    milli_wait(25);
1182  }
1183  delete pal;
1184  pal = old_pal;
1185}
1186
1187void fade_out(int steps)
1188{
1189  palette *old_pal = pal->copy();
1190  int i;
1191  for(i = 0; i < steps; i++)
1192  {
1193    uint8_t *sl1=(uint8_t *)pal->addr();
1194    uint8_t *sl2=(uint8_t *)old_pal->addr();
1195    int j;
1196    int v=(steps - i)*256 / steps;
1197    for(j = 0; j < 256; j++)
1198    {
1199      *(sl1)=((int)*(sl2))*v / 256;  sl1++; sl2++;
1200      *(sl1)=((int)*(sl2))*v / 256;  sl1++; sl2++;
1201      *(sl1)=((int)*(sl2))*v / 256;  sl1++; sl2++;
1202    }
1203    pal->load();
1204    wm->flush_screen();
1205    milli_wait(25);
1206  }
1207  screen->clear();
1208  wm->flush_screen();
1209  delete pal;
1210  pal = old_pal;
1211
1212  pal->load();
1213}
1214
1215int text_draw(int y, int x1, int y1, int x2, int y2, char const *buf, JCFont *font, uint8_t *cmap, char color);
1216
1217void do_title()
1218{
1219    if(cdc_logo == -1)
1220        return;
1221
1222    if(sound_avail & MUSIC_INITIALIZED)
1223    {
1224        if(current_song)
1225        {
1226            current_song->stop();
1227            delete current_song;
1228        }
1229        current_song = new song("music/intro.hmi");
1230        current_song->play(music_volume);
1231    }
1232
1233    void *logo_snd = LSymbol::FindOrCreate("LOGO_SND")->GetValue();
1234
1235    if(DEFINEDP(logo_snd) && (sound_avail & SFX_INITIALIZED))
1236        cache.sfx(lnumber_value(logo_snd))->play(sfx_volume);
1237
1238    // This must be a dynamic allocated image because if it
1239    // is not and the window gets closed during do_title, then
1240    // exit() will try to delete (through the desctructor of
1241    // image_list in image.cpp) the image on the stack -> boom.
1242    image *blank = new image(vec2i(2, 2));
1243    blank->clear();
1244    wm->set_mouse_shape(blank->copy(), 0, 0); // hide mouse
1245    delete blank;
1246    fade_in(cache.img(cdc_logo), 32);
1247
1248    milli_wait(400);
1249
1250    void *space_snd = LSymbol::FindOrCreate("SPACE_SND")->GetValue();
1251
1252    fade_out(32);
1253    milli_wait(100);
1254
1255    int i;
1256    char *str = lstring_value(LSymbol::FindOrCreate("plot_start")->Eval());
1257
1258    bFILE *fp = open_file("art/smoke.spe", "rb");
1259    if(!fp->open_failure())
1260    {
1261        spec_directory sd(fp);
1262        palette *old_pal = pal;
1263        pal = new palette(sd.find(SPEC_PALETTE), fp);
1264        pal->shift(1);
1265
1266        image *gray = new image(fp, sd.find("gray_pict"));
1267        image *smoke[5];
1268
1269        char nm[20];
1270        for(i = 0; i < 5; i++)
1271        {
1272            sprintf(nm, "smoke%04d.pcx", i + 1);
1273            smoke[i] = new image(fp, sd.find(nm));
1274        }
1275
1276        screen->clear();
1277        pal->load();
1278
1279        int dx = (xres + 1) / 2 - gray->Size().x / 2, dy = (yres + 1) / 2 - gray->Size().y / 2;
1280        gray->put_image(screen, dx, dy);
1281        smoke[0]->put_image(screen, dx + 24, dy + 5);
1282
1283        fade_in(NULL, 16);
1284        uint8_t cmap[32];
1285        for(i = 0; i < 32; i++)
1286        cmap[i] = pal->find_closest(i * 256 / 32, i * 256 / 32, i * 256 / 32);
1287
1288        event ev;
1289        ev.type = EV_SPURIOUS;
1290        time_marker start;
1291
1292        for(i = 0; i < 320 && (ev.type != EV_KEY && ev.type != EV_MOUSE_BUTTON); i++)
1293        {
1294            gray->put_image(screen, dx, dy);
1295            smoke[i % 5]->put_image(screen, dx + 24, dy + 5);
1296            text_draw(205 - i, dx + 15, dy, dx + 320 - 15, dy + 199, str, wm->font(), cmap, wm->bright_color());
1297            wm->flush_screen();
1298            time_marker now;
1299
1300            while(now.diff_time(&start) < 0.18)
1301            {
1302                milli_wait(20); // ECS - Added the wait, so CPU utilization stays low during the story
1303                now.get_time();
1304            }
1305
1306            start.get_time();
1307
1308            while(wm->event_waiting() && ev.type != EV_KEY)
1309            {
1310                wm->get_event(ev);
1311            }
1312            if((i % 5) == 0 && DEFINEDP(space_snd) && (sound_avail & SFX_INITIALIZED))
1313            {
1314                cache.sfx(lnumber_value(space_snd))->play(sfx_volume * 90 / 127);
1315            }
1316        }
1317
1318        the_game->reset_keymap();
1319
1320        fade_out(16);
1321
1322        for(i = 0; i < 5; i++)
1323            delete smoke[i];
1324        delete gray;
1325        delete pal;
1326        pal = old_pal;
1327    }
1328    delete fp;
1329
1330    if(title_screen >= 0)
1331        fade_in(cache.img(title_screen), 32);
1332}
1333
1334extern int start_edit;
1335
1336void Game::request_end()
1337{
1338  req_end = 1;
1339}
1340
1341extern void fast_load_start_recording(char *name);
1342extern void fast_load_stop_recording();
1343extern void fast_load_start_reloading(char *name);
1344extern void fast_load_stop_reloading();
1345
1346Game::Game(int argc, char **argv)
1347{
1348  int i;
1349  req_name[0]=0;
1350  bg_xmul = bg_ymul = 1;
1351  bg_xdiv = bg_ydiv = 8;
1352  last_input = NULL;
1353  current_automap = NULL;
1354  current_level = NULL;
1355  refresh = 1;
1356  the_game = this;
1357  top_menu = joy_win = NULL;
1358  old_view = first_view = NULL;
1359  nplayers = 1;
1360
1361  help_text_frames = 0;
1362  strcpy(help_text, "");
1363
1364
1365  for(i = 1; i < argc; i++)
1366    if(!strcmp(argv[i], "-no_delay"))
1367    {
1368      no_delay = 1;
1369      dprintf("Frame delay off (-nodelay)\n");
1370    }
1371
1372
1373  image_init();
1374  zoom = 15;
1375  no_delay = 0;
1376
1377  if(get_option("-use_joy"))
1378  {
1379    has_joystick = joy_init(argc, argv);
1380    dprintf("Joystick : ");
1381    if(has_joystick) dprintf("detected\n");
1382    else dprintf("not detected\n");
1383  }
1384  else has_joystick = 0;
1385
1386//    ProfilerInit(collectDetailed, bestTimeBase, 2000, 200); //prof
1387    char *fastpath;
1388    fastpath = (char *)malloc(strlen(get_save_filename_prefix()) + 12 + 1);
1389    sprintf(fastpath, "%sfastload.dat", get_save_filename_prefix());
1390    fast_load_start_recording(fastpath);
1391    load_data(argc, argv);
1392    fast_load_stop_recording();
1393    free(fastpath);
1394//    ProfilerDump("\pabuse.prof");  //prof
1395//    ProfilerTerm();
1396
1397  get_key_bindings();
1398
1399  reset_keymap();                   // we think all the keys are up right now
1400  finished = false;
1401
1402  calc_light_table(pal);
1403
1404  if(current_level == NULL && net_start())  // if we joined a net game get level from server
1405  {
1406    if(!request_server_entry())
1407    {
1408      exit(0);
1409    }
1410    net_reload();
1411//    load_level(NET_STARTFILE);
1412  }
1413
1414
1415  set_mode(19, argc, argv);
1416  if(get_option("-2") && (xres < 639 || yres < 399))
1417  {
1418    close_graphics();
1419    fprintf(stderr, "Resolution must be > 640x400 to use -2 option\n");
1420    exit(0);
1421  }
1422  pal->load();
1423
1424  recalc_local_view_space();   // now that we know what size the screen is...
1425
1426  dark_color = get_color(cache.img(window_colors)->Pixel(vec2i(2, 0)));
1427  bright_color = get_color(cache.img(window_colors)->Pixel(vec2i(0, 0)));
1428  med_color = get_color(cache.img(window_colors)->Pixel(vec2i(1, 0)));
1429
1430  morph_dark_color = get_color(cache.img(window_colors)->Pixel(vec2i(2, 1)));
1431  morph_bright_color = get_color(cache.img(window_colors)->Pixel(vec2i(0, 1)));
1432  morph_med_color = get_color(cache.img(window_colors)->Pixel(vec2i(1, 1)));
1433  morph_sel_frame_color = pal->find_closest(255, 255, 0);
1434  light_connection_color = morph_sel_frame_color;
1435
1436  if(NILP(symbol_value(l_default_font)))
1437  {
1438    printf("No font defined, set symbol default-font to an image name\n");
1439    exit(0);
1440  }
1441  int font_pict;
1442  if(big_font_pict != -1)
1443  {
1444    if(small_font_pict != -1)
1445    {
1446      if(xres/(start_doubled ? 2 : 1)>400)
1447      {
1448    font_pict = big_font_pict;
1449      }
1450      else font_pict = small_font_pict;
1451    } else font_pict = big_font_pict;
1452  } else font_pict = small_font_pict;
1453
1454  if(console_font_pict == -1) console_font_pict = font_pict;
1455  game_font = new JCFont(cache.img(font_pict));
1456
1457  console_font = new JCFont(cache.img(console_font_pict));
1458
1459  wm = new WindowManager(screen, pal, bright_color,
1460                         med_color, dark_color, game_font);
1461
1462  delete stat_man;  // move to a graphical status manager
1463  gui_status_manager *gstat = new gui_status_manager();
1464  gstat->set_window_title("status");
1465  stat_man = gstat;
1466
1467
1468  chat = new chat_console( console_font, 50, 6);
1469
1470  if(!wm->has_mouse())
1471  {
1472    close_graphics();
1473    image_uninit();
1474    printf("No mouse driver detected, please rectify.\n");
1475    exit(0);
1476  }
1477
1478
1479  gamma_correct(pal);
1480
1481  if(main_net_cfg == NULL || (main_net_cfg->state != net_configuration::SERVER &&
1482                 main_net_cfg->state != net_configuration::CLIENT))
1483  {
1484    if(!start_edit && !net_start())
1485      do_title();
1486  } else if(main_net_cfg && main_net_cfg->state == net_configuration::SERVER)
1487  {
1488    the_game->load_level(level_file);
1489    start_running = 1;
1490  }
1491
1492
1493  dev|= DRAW_FG_LAYER | DRAW_BG_LAYER | DRAW_PEOPLE_LAYER | DRAW_HELP_LAYER | DRAW_LIGHTS | DRAW_LINKS;
1494
1495  if(dev & EDIT_MODE)
1496    set_frame_size(0);
1497//  do_intro();
1498  state = START_STATE;         // first set the state to one that has windows
1499
1500
1501  if(start_running)
1502    set_state(RUN_STATE);
1503  else
1504  {
1505    screen->clear();
1506    if(title_screen >= 0)
1507    {
1508      image *tit = cache.img(title_screen);
1509      tit->put_image(screen, screen->Size().x/2 - tit->Size().x/2,
1510                    screen->Size().y/2 - tit->Size().y/2);
1511    }
1512    set_state(MENU_STATE);   // then go to menu state so windows will turn off
1513  }
1514}
1515
1516
1517
1518time_marker *led_last_time = NULL, *fps_mark_start = NULL;
1519double avg_fps = 15.0, possible_fps = 15.0;
1520
1521void Game::toggle_delay()
1522{
1523  no_delay=!no_delay;
1524  if(no_delay)
1525    show_help(symbol_str("delay_off"));
1526  else show_help(symbol_str("delay_on"));
1527  avg_fps = possible_fps = 15.0;
1528}
1529
1530void Game::show_time()
1531{
1532  if(first_view && fps_on)
1533  {
1534    char str[10];
1535    sprintf(str, "%ld", (long)(avg_fps * 10.0));
1536    console_font->put_string(screen, first_view->cx1, first_view->cy1, str);
1537
1538    sprintf(str, "%d", total_active);
1539    console_font->put_string(screen, first_view->cx1, first_view->cy1 + 10, str);
1540  }
1541}
1542
1543void Game::update_screen()
1544{
1545  if(state == HELP_STATE)
1546    draw_help();
1547  else if(current_level)
1548  {
1549    if(!(dev & EDIT_MODE) || refresh)
1550    {
1551      view *f = first_view;
1552      current_level->clear_active_list();
1553      for(; f; f = f->next)
1554      {
1555    if(f->focus)
1556    {
1557      int w, h;
1558
1559      w=(f->cx2 - f->cx1 + 1);
1560      h=(f->cy2 - f->cy1 + 1);
1561
1562      total_active += current_level->add_drawables(f->xoff()-w / 4, f->yoff()-h / 4,
1563                             f->xoff()+w + w / 4, f->yoff()+h + h / 4);
1564
1565    }
1566      }
1567
1568      for(f = first_view; f; f = f->next)
1569      {
1570        if(f->drawable())
1571    {
1572      if(interpolate_draw)
1573      {
1574            draw_map(f, 1);
1575        wm->flush_screen();
1576      }
1577          draw_map(f, 0);
1578    }
1579      }
1580      if(current_automap)
1581      current_automap->draw();
1582    }
1583    if(state == PAUSE_STATE)
1584    {
1585      for(view *f = first_view; f; f = f->next)
1586        cache.img(pause_image)->put_image(screen, (f->cx1 + f->cx2)/2 - cache.img(pause_image)->Size().x/2,
1587                   f->cy1 + 5, 1);
1588    }
1589
1590    show_time();
1591  }
1592
1593  if(state == RUN_STATE && cache.prof_is_on())
1594    cache.prof_poll_end();
1595
1596  wm->flush_screen();
1597
1598}
1599
1600void Game::do_intro()
1601{
1602
1603}
1604
1605int Game::calc_speed()
1606{
1607    int ret = 0;
1608    if(fps_mark_start)
1609    {
1610        time_marker t;
1611
1612        // find average fps for last 10 frames
1613        double td = t.diff_time(fps_mark_start);
1614        if(td < 0.001)     // something is rotten in the state of demark
1615            td = 0.001;
1616
1617        avg_fps = avg_fps * 9.0 / 10.0 + 1.0/(td * 10.0);
1618        possible_fps = possible_fps * 9.0 / 10.0 + 1.0/(td * 10.0);
1619
1620        if(avg_fps > 14)
1621        {
1622            if(massive_frame_panic > 20)
1623                massive_frame_panic = 20;
1624            else if(massive_frame_panic)
1625                massive_frame_panic--;
1626        }
1627
1628        if(avg_fps > 15 && ((dev & EDIT_MODE)==0 || need_delay))
1629        {
1630            frame_panic = 0;
1631            int32_t stime=(int32_t)((1 / 15.0 - 1.0 / possible_fps)*1000.0);
1632            if(stime > 0 && !no_delay)
1633            {
1634                milli_wait(stime);
1635                avg_fps -= 1.0/(td * 10.0);   // subtract out old estimate
1636
1637                time_marker t;
1638
1639                // find average fps for last 10 frames
1640                double td = t.diff_time(fps_mark_start);
1641                if(td < 0.00001)     // something is rotten in the state of demark
1642                    td = 0.00001;
1643
1644                avg_fps += 1.0/(td * 10.0);       // add in new estimate
1645            }
1646        }
1647        else if(avg_fps < 14)
1648        {
1649            if(avg_fps < 10)
1650                massive_frame_panic++;
1651            frame_panic++;
1652            ret = 1;
1653        }
1654        else if(dev & EDIT_MODE)
1655        {
1656            // ECS - Added this case and the wait.  It's a cheap hack to assure that
1657            // we don't exceed 30FPS in edit mode and hog the CPU.
1658            milli_wait(33);
1659        }
1660
1661        delete fps_mark_start;
1662    }
1663    fps_mark_start = new time_marker;
1664    return ret;
1665}
1666
1667extern int start_edit;
1668
1669void Game::get_input()
1670{
1671    event ev;
1672    idle_ticks++;
1673    while(event_waiting())
1674    {
1675        get_event(ev);
1676
1677        if(ev.type == EV_MOUSE_MOVE)
1678        {
1679            last_input = ev.window;
1680        }
1681        // don't process repeated keys in the main window, it will slow down the game to handle such
1682        // useless events. However in other windows it might be useful, such as in input windows
1683        // where you want to repeatedly scroll down...
1684        if(ev.type != EV_KEY || !key_down(ev.key) || ev.window || (dev & EDIT_MODE))
1685        {
1686            if(ev.type == EV_KEY)
1687            {
1688                set_key_down(ev.key, 1);
1689                if(playing_state(state))
1690                {
1691                    if(ev.key < 256)
1692                    {
1693                        if(chat && chat->chat_event(ev))
1694                            base->packet.write_uint8(SCMD_CHAT_KEYPRESS);
1695                        else
1696                            base->packet.write_uint8(SCMD_KEYPRESS);
1697                    }
1698                    else
1699                        base->packet.write_uint8(SCMD_EXT_KEYPRESS);
1700                    base->packet.write_uint8(client_number());
1701                    if(ev.key > 256)
1702                        base->packet.write_uint8(ev.key - 256);
1703                    else
1704                        base->packet.write_uint8(ev.key);
1705                }
1706            }
1707            else if(ev.type == EV_KEYRELEASE)
1708            {
1709                set_key_down(ev.key, 0);
1710                if(playing_state(state))
1711                {
1712                    if(ev.key < 256)
1713                        base->packet.write_uint8(SCMD_KEYRELEASE);
1714                    else
1715                        base->packet.write_uint8(SCMD_EXT_KEYRELEASE);
1716                    base->packet.write_uint8(client_number());
1717                    if(ev.key > 255)
1718                        base->packet.write_uint8(ev.key - 256);
1719                    else
1720                        base->packet.write_uint8(ev.key);
1721                }
1722            }
1723
1724            if((dev & EDIT_MODE) || start_edit || ev.type == EV_MESSAGE)
1725            {
1726                dev_cont->handle_event(ev);
1727            }
1728
1729            view *v = first_view;
1730            for(; v; v = v->next)
1731            {
1732                if(v->local_player() && v->handle_event(ev))
1733                    ev.type = EV_SPURIOUS;       // if the event was used by the view, gobble it up
1734            }
1735
1736            if(current_automap)
1737            {
1738                current_automap->handle_event(ev);
1739            }
1740
1741            help_handle_event(ev);
1742            mousex = last_demo_mx;
1743            mousey = last_demo_my;
1744
1745            if(ev.type == EV_MESSAGE)
1746            {
1747                switch (ev.message.id)
1748                {
1749                    case CALB_JOY:
1750                    {
1751                        if(!joy_win)
1752                        {
1753                            joy_win = wm->new_window(80, 50, -1, -1,
1754                                    new button(70, 9, JOY_OK, "OK",
1755                                    new info_field(0, 30, DEV_NULL,
1756                                    " Center joystick and\n"
1757                                    "press the fire button", NULL)),
1758                                    "Joystick");
1759                            set_state(JOY_CALB_STATE);
1760                        }
1761                    }
1762                    case TOP_MENU:
1763                    {
1764                        menu_select(ev);
1765                    } break;
1766                    case DEV_QUIT:
1767                    {
1768                        finished = true;
1769                    } break;
1770                }
1771            }
1772            else if(ev.type == EV_CLOSE_WINDOW && ev.window == top_menu)
1773            {
1774                wm->close_window(top_menu);
1775                top_menu = NULL;
1776            }
1777
1778            switch(state)
1779            {
1780                case JOY_CALB_STATE:
1781                {
1782                    joy_calb(ev);
1783                } break;
1784                case INTRO_START_STATE:
1785                {
1786                    do_intro();
1787                    if(dev & EDIT_MODE)
1788                        set_state(RUN_STATE);
1789                    else
1790                        set_state(MENU_STATE);
1791                } break;
1792                case PAUSE_STATE:
1793                {
1794                    if(ev.type == EV_KEY && (ev.key == JK_SPACE || ev.key == JK_ENTER))
1795                    {
1796                        set_state(RUN_STATE);
1797                    }
1798                } break;
1799                case RUN_STATE:
1800                {
1801                    if(ev.window == NULL)
1802                    {
1803                        switch (ev.type)
1804                        {
1805                            case EV_KEY:
1806                            {
1807                                switch (ev.key)
1808                                {
1809                                    case 'm':
1810                                    {
1811                                        if(dev & MAP_MODE)
1812                                            dev -= MAP_MODE;
1813                                        else if((player_list && player_list->next) || dev & EDIT_MODE)
1814                                            dev |= MAP_MODE;
1815
1816                                        if(!(dev & MAP_MODE))
1817                                        {
1818                                            if(dev_cont->tbw)
1819                                                dev_cont->toggle_toolbar();
1820                                            edit_mode = ID_DMODE_DRAW;
1821                                        }
1822                                        need_refresh();
1823                                    } break;
1824                                    case 'v':
1825                                    {
1826                                        wm->push_event(new event(DO_VOLUME, NULL));
1827                                    } break;
1828                                    case 'p':
1829                                    {
1830                                        if(!(dev & EDIT_MODE) && (!main_net_cfg ||
1831                                            (main_net_cfg->state != net_configuration::SERVER &&
1832                                            main_net_cfg->state != net_configuration::CLIENT)))
1833                                        {
1834                                            set_state(PAUSE_STATE);
1835                                        }
1836                                    } break;
1837                                    case 'S':
1838                                    {
1839                                        if(start_edit)
1840                                        {
1841                                            wm->push_event(new event(ID_LEVEL_SAVE, NULL));
1842                                        }
1843                                    } break;
1844                                    case JK_TAB:
1845                                        if(start_edit)
1846                                            toggle_edit_mode();
1847                                        need_refresh();
1848                                        break;
1849                                    case 'c':
1850                                    case 'C':
1851                                        if(chatting_enabled && (!(dev & EDIT_MODE) && chat))
1852                                            chat->toggle();
1853                                        break;
1854                                    case '9':
1855                                        dev = dev ^ PERFORMANCE_TEST_MODE;
1856                                        need_refresh();
1857                                        break;
1858                                }
1859                            } break;
1860                            case EV_RESIZE:
1861                            {
1862                                view *v;
1863                                for(v = first_view; v; v = v->next)  // see if any views need to change size
1864                                {
1865                                    if(v->local_player())
1866                                    {
1867                                        int w = (xres - 10)/(small_render ? 2 : 1);
1868                                        int h = (yres - 10)/(small_render ? 2 : 1);
1869
1870                                        v->suggest.send_view = 1;
1871                                        v->suggest.cx1 = 5;
1872                                        v->suggest.cx2 = 5 + w;
1873                                        v->suggest.cy1 = 5;
1874                                        v->suggest.cy2 = 5 + h;
1875                                        v->suggest.pan_x = v->pan_x;
1876                                        v->suggest.pan_y = v->pan_y;
1877                                        v->suggest.shift_down = v->shift_down;
1878                                        v->suggest.shift_right = v->shift_right;
1879                                    }
1880                                }
1881                                draw();
1882                            } break;
1883                            case EV_REDRAW:
1884                            {
1885                                screen->AddDirty(ev.redraw.x1, ev.redraw.y1,
1886                                    ev.redraw.x2 + 1, ev.redraw.y2 + 1);
1887                            } break;
1888                            case EV_MESSAGE:
1889                            {
1890                                switch (ev.message.id)
1891                                {
1892                                    case RAISE_SFX:
1893                                    case LOWER_SFX:
1894                                    case RAISE_MUSIC:
1895                                    case LOWER_MUSIC:
1896                                    {
1897                                        if(ev.message.id == RAISE_SFX && sfx_volume != 127)
1898                                            sfx_volume = Min(127, sfx_volume + 16);
1899                                        if(ev.message.id == LOWER_SFX && sfx_volume != 0)
1900                                            sfx_volume = Max(sfx_volume - 16, 0);
1901                                        if(ev.message.id == RAISE_MUSIC && music_volume != 126)
1902                                        {
1903                                            music_volume = Min(music_volume + 16, 127);
1904                                            if(current_song && (sound_avail & MUSIC_INITIALIZED))
1905                                                current_song->set_volume(music_volume);
1906                                        }
1907
1908                                        if(ev.message.id == LOWER_MUSIC && music_volume != 0)
1909                                        {
1910                                            music_volume = Max(music_volume - 16, 0);
1911                                            if(current_song && (sound_avail & MUSIC_INITIALIZED))
1912                                                current_song->set_volume(music_volume);
1913                                        }
1914
1915                                        ((button *)ev.message.data)->push();
1916/*                                        volume_window->inm->redraw();
1917                                        draw_value(volume_window->screen, 2, 43,
1918                                                (volume_window->x2()-volume_window->x1()-1), 8, sfx_volume, 127);
1919                                        draw_value(volume_window->screen, 2, 94,
1920                                                (volume_window->x2()-volume_window->x1()-1), 8, music_volume, 127);
1921*/
1922                                        break;
1923                                    }
1924                                }
1925                            }
1926                        }
1927                    }
1928                } break;
1929            }
1930        }
1931    }
1932}
1933
1934
1935void net_send(int force = 0)
1936{
1937  if((!(dev & EDIT_MODE)) || force)
1938  {
1939    if(demo_man.state == demo_manager::PLAYING)
1940    {
1941      base->input_state = INPUT_PROCESSING;
1942    } else
1943    {
1944
1945
1946
1947      if(!player_list->focus)
1948      {
1949    dprintf("Players have not been created\ncall create_players");
1950    exit(0);
1951      }
1952
1953
1954      view *p = player_list;
1955      for(; p; p = p->next)
1956        if(p->local_player())
1957      p->get_input();
1958
1959
1960      base->packet.write_uint8(SCMD_SYNC);
1961      base->packet.write_uint16(make_sync());
1962
1963      if(base->join_list)
1964      base->packet.write_uint8(SCMD_RELOAD);
1965
1966      //      printf("save tick %d, pk size=%d, rand_on=%d, sync=%d\n", current_level->tick_counter(),
1967      //         base->packet.packet_size(), rand_on, make_sync());
1968      send_local_request();
1969    }
1970  }
1971}
1972
1973void net_receive()
1974{
1975  if(!(dev & EDIT_MODE) && current_level)
1976  {
1977    uint8_t buf[PACKET_MAX_SIZE + 1];
1978    int size;
1979
1980    if(demo_man.state == demo_manager::PLAYING)
1981    {
1982      if(!demo_man.get_packet(buf, size))
1983        size = 0;
1984      base->packet.packet_reset();
1985      base->mem_lock = 0;
1986    } else
1987    {
1988      size = get_inputs_from_server(buf);
1989      if(demo_man.state == demo_manager::RECORDING)
1990    demo_man.save_packet(buf, size);
1991    }
1992
1993    process_packet_commands(buf, size);
1994  }
1995}
1996
1997void Game::step()
1998{
1999  clear_tmp();
2000  if(current_level)
2001  {
2002    current_level->unactivate_all();
2003    total_active = 0;
2004    for(view *f = first_view; f; f = f->next)
2005    {
2006      if(f->focus)
2007      {
2008    f->update_scroll();
2009    int w, h;
2010
2011    w=(f->cx2 - f->cx1 + 1);
2012    h=(f->cy2 - f->cy1 + 1);
2013        total_active += current_level->add_actives(f->xoff()-w / 4, f->yoff()-h / 4,
2014                         f->xoff()+w + w / 4, f->yoff()+h + h / 4);
2015      }
2016    }
2017  }
2018
2019  if(state == RUN_STATE)
2020  {
2021    if((dev & EDIT_MODE) || (main_net_cfg && (main_net_cfg->state == net_configuration::CLIENT ||
2022                         main_net_cfg->state == net_configuration::SERVER)))
2023      idle_ticks = 0;
2024
2025    if(demo_man.current_state()==demo_manager::NORMAL && idle_ticks > 420 && demo_start)
2026    {
2027      idle_ticks = 0;
2028      set_state(MENU_STATE);
2029    }
2030    else if(!(dev & EDIT_MODE))               // if edit mode, then don't step anything
2031    {
2032      if(key_down(JK_ESC))
2033      {
2034    set_state(MENU_STATE);
2035    set_key_down(JK_ESC, 0);
2036      }
2037      ambient_ramp = 0;
2038      view *v;
2039      for(v = first_view; v; v = v->next)
2040        v->update_scroll();
2041
2042      cache.prof_poll_start();
2043      current_level->tick();
2044      sbar.step();
2045    } else
2046      dev_scroll();
2047  } else if(state == JOY_CALB_STATE)
2048  {
2049    event ev;
2050    joy_calb(ev);
2051  } else if(state == MENU_STATE)
2052    main_menu();
2053
2054  if((key_down('x') || key_down(JK_F4))
2055      && (key_down(JK_ALT_L) || key_down(JK_ALT_R))
2056      && confirm_quit())
2057    finished = true;
2058}
2059
2060extern void *current_demo;
2061
2062Game::~Game()
2063{
2064  current_demo = NULL;
2065  if(first_view == player_list) first_view = NULL;
2066  while(player_list)
2067  {
2068    view *p = player_list;
2069    game_object *o = p->focus;
2070    player_list = player_list->next;
2071    delete p;
2072    o->set_controller(NULL);
2073    if(current_level && o)
2074      current_level->delete_object(o);
2075    else delete o;
2076  }
2077
2078  if(current_level) { delete current_level; current_level = NULL; }
2079
2080  if(first_view != player_list)
2081  {
2082    while(player_list)
2083    {
2084      view *p = player_list;
2085      player_list = player_list->next;
2086      delete p;
2087    }
2088  }
2089
2090  while(first_view)
2091  {
2092    view *p = first_view;
2093    first_view = first_view->next;
2094    delete p;
2095  }
2096
2097  player_list = NULL;
2098
2099  if(old_view)
2100  {
2101    first_view = old_view;
2102    while(first_view)
2103    {
2104      view *p = first_view;
2105      first_view = first_view->next;
2106      delete p;
2107    }
2108  }
2109  old_view = NULL;
2110
2111  int i = 0;
2112  for(; i < total_objects; i++)
2113  {
2114    free(object_names[i]);
2115    delete figures[i];
2116  }
2117  free_pframes();
2118  if(fps_mark_start) delete fps_mark_start; fps_mark_start = NULL;
2119  delete pal;
2120  free(object_names);
2121  free(figures);
2122
2123  free(backtiles);
2124  free(foretiles);
2125  if(total_weapons)
2126    free(weapon_types);
2127
2128  config_cleanup();
2129  delete color_table;
2130  delete wm;
2131  delete game_font;
2132  delete big_font;
2133  delete console_font;
2134  if(total_help_screens)
2135    free(help_screens);
2136
2137  close_graphics();
2138  image_uninit();
2139}
2140
2141
2142
2143void Game::draw(int scene_mode)
2144{
2145    screen->AddDirty(0, 0, xres + 1, yres + 1);
2146
2147    screen->clear();
2148
2149    if(scene_mode)
2150    {
2151        char const *helpstr = "ARROW KEYS CHANGE TEXT SPEED";
2152        wm->font()->put_string(screen, screen->Size().x/2-(wm->font()->width()*strlen(helpstr))/2 + 1,
2153            screen->Size().y-wm->font()->height()-5 + 1, helpstr, wm->dark_color());
2154        wm->font()->put_string(screen, screen->Size().x/2-(wm->font()->width()*strlen(helpstr))/2,
2155            screen->Size().y-wm->font()->height()-5, helpstr, wm->bright_color());
2156    }
2157/*    else
2158    {
2159        char *helpstr="PRESS h FOR HELP";
2160        wm->font()->put_string(screen, screen->Size().x-wm->font()->width()*strlen(helpstr)-5,
2161            screen->Size().y-wm->font()->height()-5, helpstr);
2162    }*/
2163/*    int dc = cache.img(window_colors)->pixel(0, 2);
2164    int mc = cache.img(window_colors)->pixel(1, 2);
2165    int bc = cache.img(window_colors)->pixel(2, 2);
2166    screen->line(0, 0, screen->Size().x-1, 0, dc);
2167    screen->line(0, 0, 0, screen->Size().y-1, dc);
2168    screen->line(0, screen->Size().y-1, screen->Size().x-1, screen->Size().y-1, bc);
2169    screen->line(screen->Size().x-1, 0, screen->Size().x-1, screen->Size().y-1, bc); */
2170
2171    for(view *f = first_view; f; f = f->next)
2172        draw_map(f, 0);
2173
2174    sbar.redraw(screen);
2175}
2176
2177int external_print = 0;
2178
2179void start_sound(int argc, char **argv)
2180{
2181  sfx_volume = music_volume = 127;
2182
2183  for(int i = 1; i < argc; i++)
2184    if(!strcmp(argv[i], "-sfx_volume"))
2185    {
2186      i++;
2187      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2188        sfx_volume = atoi(argv[i]);
2189      else printf("Bad sound effects volume level, use 0..127\n");
2190    }
2191    else if(!strcmp(argv[i], "-music_volume"))
2192    {
2193      i++;
2194      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2195        music_volume = atoi(argv[i]);
2196      else printf("Bad music volume level, use 0..127\n");
2197    }
2198
2199  sound_avail = sound_init(argc, argv);
2200}
2201
2202void game_printer(char *st)
2203{
2204  if(dev_console && !external_print)
2205  {
2206    dev_console->put_string(st);
2207  }
2208  else fprintf(stderr, "%s", st);
2209}
2210
2211
2212void game_getter(char *st, int max)
2213{
2214  if(!max) return;
2215  max--;
2216  *st = 0;
2217  if(dev_console && !external_print)
2218  {
2219    dev_console->show();
2220    int t = 0;
2221    event ev;
2222    do
2223    {
2224      get_event(ev);
2225      if(ev.type == EV_KEY)
2226      {
2227    if(ev.key == JK_BACKSPACE)
2228    {
2229      if(t)
2230      {
2231        dev_console->print_f("%c", ev.key);
2232        t--;
2233        st--;
2234        *st = 0;
2235        max++;
2236      }
2237    } else if(ev.key>=' ' && ev.key<='~')
2238    {
2239      dev_console->print_f("%c", ev.key);
2240      *st = ev.key;
2241      t++;
2242      max--;
2243      st++;
2244      *st = 0;
2245    }
2246      }
2247      wm->flush_screen();
2248    } while(ev.type != EV_KEY || ev.key != JK_ENTER);
2249    dprintf("\n");
2250  }
2251  else
2252  {
2253    if(fgets(st, max, stdin))
2254    {
2255      if(*st)
2256        st[strlen(st)-1]=0;
2257    }
2258  }
2259}
2260
2261
2262void show_startup()
2263{
2264    dprintf("Abuse version %s\n", PACKAGE_VERSION);
2265}
2266
2267char *get_line(int open_braces)
2268{
2269  char *line=(char *)malloc(1000);
2270  fgets(line, 1000, stdin);
2271
2272  char prev=' ';
2273  for(char *s = line; *s && (prev!=' ' || *s!=';'); s++)
2274  {
2275    prev=*s;
2276    if(*s=='(') open_braces++;
2277    else if(*s==')') open_braces--;
2278  }
2279  if(open_braces < 0)
2280    fprintf(stderr, "\nToo many)'s\n");
2281  else if(open_braces > 0)
2282  {
2283    char *s2 = get_line(open_braces);
2284    line=(char *)realloc(line, strlen(line)+strlen(s2)+1);
2285    strcat(line, s2);
2286    free(s2);
2287  }
2288  return line;
2289}
2290
2291void check_for_lisp(int argc, char **argv)
2292{
2293    for(int i = 1; i < argc; i++)
2294    {
2295        if(!strcmp(argv[i], "-lisp"))
2296        {
2297            lisp_init(0xf000, 0x30000);
2298            char const *eof_char = "Ctrl-D";
2299            fprintf(stderr,
2300                    " CLIVE (C) 1995 Jonathan Clark, all rights reserved\n"
2301                    "   (C LISP interpreter and various extentions)\n"
2302                    "Type (%s) to exit\n", eof_char);
2303
2304            while(!feof(stdin))
2305            {
2306                fprintf(stderr, "Lisp> ");
2307                char *l = get_line(0);
2308                char const *s = l;
2309                while(*s)
2310                {
2311                    LObject *prog = LObject::Compile(s);
2312                    l_user_stack.push(prog);
2313                    while(*s==' ' || *s=='\t' || *s=='\r' || *s=='\n') s++;
2314                    prog->Eval()->Print();
2315                    l_user_stack.pop(1);
2316                }
2317                free(l);
2318            }
2319            fprintf(stderr, "End of input : bye\n");
2320            exit(0);
2321        }
2322    }
2323}
2324
2325
2326void music_check()
2327{
2328  if(sound_avail & MUSIC_INITIALIZED)
2329  {
2330    if(current_song && !current_song->playing())
2331    {
2332      current_song->play();
2333      dprintf("song finished\n");
2334    }
2335    if(!current_song)
2336    {
2337
2338      current_song = new song("music/intro.hmi");
2339      current_song->play(music_volume);
2340
2341/*      if(DEFINEDP(symbol_function(l_next_song)))  // if user function installed, call it to load up next song
2342      {
2343    int sp = current_space;
2344    current_space = PERM_SPACE;
2345    ((LSymbol *)l_next_song)->EvalFunction(NULL);
2346    current_space = sp;
2347      } */
2348    }
2349  }
2350}
2351
2352void setup(int argc, char **argv);
2353
2354void share_end();
2355void show_end();
2356
2357void show_sell(int abortable);
2358
2359extern pmenu *dev_menu;
2360
2361void game_net_init(int argc, char **argv)
2362{
2363  int nonet=!net_init(argc, argv);
2364  if(nonet)
2365    dprintf("No network driver, or network driver returned failure\n");
2366  else
2367  {
2368    set_file_opener(open_nfs_file);
2369    if(main_net_cfg && main_net_cfg->state == net_configuration::CLIENT)
2370    {
2371      if(set_file_server(net_server))
2372      start_running = 1;
2373      else
2374      {
2375                dprintf("Unable to attach to server, quitting\n");
2376                exit(0);
2377      }
2378    } else
2379    {
2380      int i;
2381      for(i = 1; i < argc - 1; i++)
2382      if(!strcmp(argv[i], "-fs"))
2383      if(!set_file_server(argv[i + 1]))
2384      dprintf("could not set default file server to %s\n", argv[i + 1]);
2385    }
2386  }
2387
2388}
2389
2390int main(int argc, char *argv[])
2391{
2392    start_argc = argc;
2393    start_argv = argv;
2394
2395    for (int i = 0; i < argc; i++)
2396    {
2397        if (!strcmp(argv[i], "-cprint"))
2398            external_print = 1;
2399    }
2400
2401#if (defined(__APPLE__) && !defined(__MACH__))
2402    unsigned char km[16];
2403
2404    fprintf(stderr, "Mac Options: ");
2405    xres = 320; yres = 200;
2406    GetKeys((uint32_t*)&km);
2407    if ((km[ 0x3a >>3] >> (0x3a & 7)) &1 != 0)
2408    {
2409        dev|=EDIT_MODE;
2410        start_edit = 1;
2411        start_running = 1;
2412        disable_autolight = 1;
2413        fprintf(stderr, "Edit Mode...");
2414    }
2415    if ((km[ 0x3b >>3] >> (0x3b & 7)) &1 != 0)
2416    {
2417        PixMult = 1;
2418        fprintf(stderr, "Single Pixel...");
2419    }
2420    else
2421    {
2422        PixMult = 2;
2423        fprintf(stderr, "Double Pixel...");
2424    }
2425    if ((km[ 0x38 >>3] >> (0x38 & 7)) &1 != 0)
2426    {
2427        xres *= 2;  yres *= 2;
2428        fprintf(stderr, "Double Size...");
2429    }
2430    fprintf(stderr, "\n");
2431
2432    if (tcpip.installed())
2433        fprintf(stderr, "Using %s\n", tcpip.name());
2434#endif
2435
2436    set_dprinter(game_printer);
2437    set_dgetter(game_getter);
2438    set_no_space_handler(handle_no_space);
2439
2440    setup(argc, argv);
2441
2442    show_startup();
2443
2444    start_sound(argc, argv);
2445
2446    stat_man = new text_status_manager();
2447    if (!get_option("-no_timer"))
2448        timer_init();
2449
2450    // look to see if we are supposed to fetch the data elsewhere
2451    if (getenv("ABUSE_PATH"))
2452        set_filename_prefix(getenv("ABUSE_PATH"));
2453
2454    // look to see if we are supposed to save the data elsewhere
2455    if (getenv("ABUSE_SAVE_PATH"))
2456        set_save_filename_prefix(getenv("ABUSE_SAVE_PATH"));
2457
2458    jrand_init();
2459    jrand(); // so compiler doesn't complain
2460
2461    set_spec_main_file("abuse.spe");
2462    check_for_lisp(argc, argv);
2463
2464    do
2465    {
2466        if (main_net_cfg && !main_net_cfg->notify_reset())
2467        {
2468            if (!get_option("-no_timer"))
2469                timer_uninit();
2470            sound_uninit();
2471            exit(0);
2472        }
2473
2474        game_net_init(argc, argv);
2475        lisp_init(0x80000, 0x94000);
2476
2477        dev_init(argc, argv);
2478
2479        Game *g = new Game(argc, argv);
2480
2481        dev_cont = new dev_controll();
2482        dev_cont->load_stuff();
2483
2484        g->get_input(); // prime the net
2485
2486        for (int i = 1; i + 1 < argc; i++)
2487        {
2488            if (!strcmp(argv[i], "-server"))
2489            {
2490                if (!become_server(argv[i + 1]))
2491                {
2492                    dprintf("unable to become a server\n");
2493                    exit(0);
2494                }
2495                break;
2496            }
2497        }
2498
2499        if (main_net_cfg)
2500            wait_min_players();
2501
2502        net_send(1);
2503        if (net_start())
2504        {
2505            g->step(); // process all the objects in the world
2506            g->calc_speed();
2507            g->update_screen(); // redraw the screen with any changes
2508        }
2509
2510        while (!g->done())
2511        {
2512            music_check();
2513
2514            if (req_end)
2515            {
2516                delete current_level; current_level = NULL;
2517
2518                show_end();
2519
2520                the_game->set_state(MENU_STATE);
2521                req_end = 0;
2522            }
2523
2524            if (demo_man.current_state() == demo_manager::NORMAL)
2525                net_receive();
2526
2527            // see if a request for a level load was made during the last tick
2528            if (req_name[0])
2529            {
2530                g->load_level(req_name);
2531                req_name[0] = 0;
2532                g->draw(g->state == SCENE_STATE);
2533            }
2534
2535            //if (demo_man.current_state() != demo_manager::PLAYING)
2536                g->get_input();
2537
2538            if (demo_man.current_state() == demo_manager::NORMAL)
2539                net_send();
2540            else
2541                demo_man.do_inputs();
2542
2543            service_net_request();
2544
2545            // process all the objects in the world
2546            g->step();
2547            server_check();
2548            g->calc_speed();
2549
2550            // see if a request for a level load was made during the last tick
2551            if (!req_name[0])
2552                g->update_screen(); // redraw the screen with any changes
2553        }
2554
2555        net_uninit();
2556
2557        if (net_crcs)
2558            net_crcs->clean_up();
2559        delete net_crcs; net_crcs = NULL;
2560
2561        delete chat;
2562
2563        milli_wait(500);
2564
2565        delete small_render; small_render = NULL;
2566
2567        if (current_song)
2568            current_song->stop();
2569        delete current_song; current_song = NULL;
2570
2571        cache.empty();
2572
2573        delete dev_console; dev_console = NULL;
2574        delete dev_menu; dev_menu = NULL;
2575        delete g; g = NULL;
2576        delete old_pal; old_pal = NULL;
2577
2578        compiled_uninit();
2579        delete_all_lights();
2580        free(white_light_initial);
2581
2582        for (int i = 0; i < TTINTS; i++)
2583            free(tints[i]);
2584
2585        dev_cleanup();
2586        delete dev_cont; dev_cont = NULL;
2587        delete stat_man; stat_man = new text_status_manager();
2588
2589        if (!(main_net_cfg && main_net_cfg->restart_state()))
2590        {
2591            LSymbol *end_msg = LSymbol::FindOrCreate("end_msg");
2592            if (DEFINEDP(end_msg->GetValue()))
2593                printf("%s\n", lstring_value(end_msg->GetValue()));
2594        }
2595
2596        lisp_uninit();
2597
2598        base->packet.packet_reset();
2599    }
2600    while (main_net_cfg && main_net_cfg->restart_state());
2601
2602    delete stat_man;
2603    delete main_net_cfg; main_net_cfg = NULL;
2604
2605    set_filename_prefix(NULL);  // dealloc this mem if there was any
2606    set_save_filename_prefix(NULL);
2607
2608    if (!get_option("-no_timer"))
2609        timer_uninit();
2610
2611    l_user_stack.clean_up();
2612    // FIXME: this is now private in PtrRef::stack
2613    //l_ptr_stack.clean_up();
2614
2615    sound_uninit();
2616
2617    return 0;
2618}
2619
Note: See TracBrowser for help on using the repository browser.