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

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