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

Last change on this file since 120 was 120, checked in by Sam Hocevar, 12 years ago
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;
62WindowManager *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 WindowManager(screen, pal, bright_color,
1486                         med_color, dark_color, game_font);
1487
1488  delete stat_man;  // move to a graphical status manager
1489  gui_status_manager *gstat = new gui_status_manager();
1490  gstat->set_window_title("status");
1491  stat_man = gstat;
1492
1493
1494  chat = new chat_console( console_font, 50, 6);
1495
1496  if(!wm->has_mouse())
1497  {
1498    close_graphics();
1499    image_uninit();
1500    printf("No mouse driver detected, please rectify.\n");
1501    exit(0);
1502  }
1503
1504
1505  gamma_correct(pal);
1506
1507  if(main_net_cfg == NULL || (main_net_cfg->state != net_configuration::SERVER &&
1508                 main_net_cfg->state != net_configuration::CLIENT))
1509  {
1510    if(!start_edit && !net_start())
1511      do_title();
1512  } else if(main_net_cfg && main_net_cfg->state == net_configuration::SERVER)
1513  {
1514    the_game->load_level(level_file);
1515    start_running = 1;
1516  }
1517
1518
1519  dev|= DRAW_FG_LAYER | DRAW_BG_LAYER | DRAW_PEOPLE_LAYER | DRAW_HELP_LAYER | DRAW_LIGHTS | DRAW_LINKS;
1520
1521  if(dev & EDIT_MODE)
1522    set_frame_size(0);
1523//  do_intro();
1524  state = START_STATE;         // first set the state to one that has windows
1525
1526
1527  if(start_running)
1528    set_state(RUN_STATE);
1529  else
1530  {
1531    screen->clear();
1532    if(title_screen >= 0)
1533    {
1534      image *tit = cash.img(title_screen);
1535      tit->put_image(screen, screen->width()/2 - tit->width()/2,
1536                    screen->height()/2 - tit->height()/2);
1537    }
1538    set_state(MENU_STATE);   // then go to menu state so windows will turn off
1539  }
1540}
1541
1542
1543
1544time_marker *led_last_time = NULL, *fps_mark_start = NULL;
1545double avg_fps = 15.0, possible_fps = 15.0;
1546
1547void game::toggle_delay()
1548{
1549  no_delay=!no_delay;
1550  if(no_delay)
1551    show_help(symbol_str("delay_off"));
1552  else show_help(symbol_str("delay_on"));
1553  avg_fps = possible_fps = 15.0;
1554}
1555
1556void game::show_time()
1557{
1558  if(first_view && fps_on)
1559  {
1560    char str[10];
1561    sprintf(str, "%ld", (long)(avg_fps * 10.0));
1562    console_font->put_string(screen, first_view->cx1, first_view->cy1, str);
1563
1564    sprintf(str, "%d", total_active);
1565    console_font->put_string(screen, first_view->cx1, first_view->cy1 + 10, str);
1566  }
1567}
1568
1569void game::update_screen()
1570{
1571  if(state == HELP_STATE)
1572    draw_help();
1573  else if(current_level)
1574  {
1575    if(!(dev & EDIT_MODE) || refresh)
1576    {
1577      view *f = first_view;
1578      current_level->clear_active_list();
1579      for(; f; f = f->next)
1580      {
1581    if(f->focus)
1582    {
1583      int w, h;
1584
1585      w=(f->cx2 - f->cx1 + 1);
1586      h=(f->cy2 - f->cy1 + 1);
1587
1588      total_active += current_level->add_drawables(f->xoff()-w / 4, f->yoff()-h / 4,
1589                             f->xoff()+w + w / 4, f->yoff()+h + h / 4);
1590
1591    }
1592      }
1593
1594      for(f = first_view; f; f = f->next)
1595      {
1596        if(f->drawable())
1597    {
1598      if(interpolate_draw)
1599      {
1600            draw_map(f, 1);
1601        wm->flush_screen();
1602      }
1603          draw_map(f, 0);
1604    }
1605      }
1606      if(current_automap)
1607      current_automap->draw();
1608    }
1609    if(state == PAUSE_STATE)
1610    {
1611      for(view *f = first_view; f; f = f->next)
1612        cash.img(pause_image)->put_image(screen, (f->cx1 + f->cx2)/2 - cash.img(pause_image)->width()/2,
1613                   f->cy1 + 5, 1);
1614    }
1615
1616    show_time();
1617  }
1618
1619  if(state == RUN_STATE && cash.prof_is_on())
1620    cash.prof_poll_end();
1621
1622  wm->flush_screen();
1623
1624}
1625
1626void game::do_intro()
1627{
1628
1629}
1630
1631int game::calc_speed()
1632{
1633    int ret = 0;
1634    if(fps_mark_start)
1635    {
1636        time_marker t;
1637
1638        // find average fps for last 10 frames
1639        double td = t.diff_time(fps_mark_start);
1640        if(td < 0.001)     // something is rotten in the state of demark
1641            td = 0.001;
1642
1643        avg_fps = avg_fps * 9.0 / 10.0 + 1.0/(td * 10.0);
1644        possible_fps = possible_fps * 9.0 / 10.0 + 1.0/(td * 10.0);
1645
1646        if(avg_fps > 14)
1647        {
1648            if(massive_frame_panic > 20)
1649                massive_frame_panic = 20;
1650            else if(massive_frame_panic)
1651                massive_frame_panic--;
1652        }
1653
1654        if(avg_fps > 15 && ((dev & EDIT_MODE)==0 || need_delay))
1655        {
1656            frame_panic = 0;
1657            int32_t stime=(int32_t)((1 / 15.0 - 1.0 / possible_fps)*1000.0);
1658            if(stime > 0 && !no_delay)
1659            {
1660                milli_wait(stime);
1661                avg_fps -= 1.0/(td * 10.0);   // subtract out old estimate
1662
1663                time_marker t;
1664
1665                // find average fps for last 10 frames
1666                double td = t.diff_time(fps_mark_start);
1667                if(td < 0.00001)     // something is rotten in the state of demark
1668                    td = 0.00001;
1669
1670                avg_fps += 1.0/(td * 10.0);       // add in new estimate
1671            }
1672        }
1673        else if(avg_fps < 14)
1674        {
1675            if(avg_fps < 10)
1676                massive_frame_panic++;
1677            frame_panic++;
1678            ret = 1;
1679        }
1680        else if(dev & EDIT_MODE)
1681        {
1682            // ECS - Added this case and the wait.  It's a cheap hack to assure that
1683            // we don't exceed 30FPS in edit mode and hog the CPU.
1684            milli_wait(33);
1685        }
1686
1687        delete fps_mark_start;
1688    }
1689    fps_mark_start = new time_marker;
1690    return ret;
1691}
1692
1693extern int start_edit;
1694
1695void game::get_input()
1696{
1697    event ev;
1698    idle_ticks++;
1699    while(event_waiting())
1700    {
1701        get_event(ev);
1702
1703        if(ev.type == EV_MOUSE_MOVE)
1704        {
1705            last_input = ev.window;
1706        }
1707        // don't process repeated keys in the main window, it will slow down the game to handle such
1708        // useless events. However in other windows it might be useful, such as in input windows
1709        // where you want to repeatedly scroll down...
1710        if(ev.type != EV_KEY || !key_down(ev.key) || ev.window || (dev & EDIT_MODE))
1711        {
1712            if(ev.type == EV_KEY)
1713            {
1714                set_key_down(ev.key, 1);
1715                if(playing_state(state))
1716                {
1717                    if(ev.key < 256)
1718                    {
1719                        if(chat && chat->chat_event(ev))
1720                            base->packet.write_uint8(SCMD_CHAT_KEYPRESS);
1721                        else
1722                            base->packet.write_uint8(SCMD_KEYPRESS);
1723                    }
1724                    else
1725                        base->packet.write_uint8(SCMD_EXT_KEYPRESS);
1726                    base->packet.write_uint8(client_number());
1727                    if(ev.key > 256)
1728                        base->packet.write_uint8(ev.key - 256);
1729                    else
1730                        base->packet.write_uint8(ev.key);
1731                }
1732            }
1733            else if(ev.type == EV_KEYRELEASE)
1734            {
1735                set_key_down(ev.key, 0);
1736                if(playing_state(state))
1737                {
1738                    if(ev.key < 256)
1739                        base->packet.write_uint8(SCMD_KEYRELEASE);
1740                    else
1741                        base->packet.write_uint8(SCMD_EXT_KEYRELEASE);
1742                    base->packet.write_uint8(client_number());
1743                    if(ev.key > 255)
1744                        base->packet.write_uint8(ev.key - 256);
1745                    else
1746                        base->packet.write_uint8(ev.key);
1747                }
1748            }
1749
1750            if((dev & EDIT_MODE) || start_edit || ev.type == EV_MESSAGE)
1751            {
1752                dev_cont->handle_event(ev);
1753            }
1754
1755            view *v = first_view;
1756            for(; v; v = v->next)
1757            {
1758                if(v->local_player() && v->handle_event(ev))
1759                    ev.type = EV_SPURIOUS;       // if the event was used by the view, gobble it up
1760            }
1761
1762            if(current_automap)
1763            {
1764                current_automap->handle_event(ev);
1765            }
1766
1767            help_handle_event(ev);
1768            mousex = last_demo_mx;
1769            mousey = last_demo_my;
1770
1771            if(ev.type == EV_MESSAGE)
1772            {
1773                switch (ev.message.id)
1774                {
1775                    case CALB_JOY:
1776                    {
1777                        if(!joy_win)
1778                        {
1779                            joy_win = wm->new_window(80, 50, -1, -1,
1780                                    new button(70, 9, JOY_OK, "OK",
1781                                    new info_field(0, 30, DEV_NULL,
1782                                    " Center joystick and\n"
1783                                    "press the fire button", NULL)),
1784                                    "Joystick");
1785                            set_state(JOY_CALB_STATE);
1786                        }
1787                    }
1788                    case TOP_MENU:
1789                    {
1790                        menu_select(ev);
1791                    } break;
1792                    case DEV_QUIT:
1793                    {
1794                        finished = 1;
1795                    } break;
1796                }
1797            }
1798            else if(ev.type == EV_CLOSE_WINDOW && ev.window == top_menu)
1799            {
1800                wm->close_window(top_menu);
1801                top_menu = NULL;
1802            }
1803
1804            switch(state)
1805            {
1806                case JOY_CALB_STATE:
1807                {
1808                    joy_calb(ev);
1809                } break;
1810                case INTRO_START_STATE:
1811                {
1812                    do_intro();
1813                    if(dev & EDIT_MODE)
1814                        set_state(RUN_STATE);
1815                    else
1816                        set_state(MENU_STATE);
1817                } break;
1818                case PAUSE_STATE:
1819                {
1820                    if(ev.type == EV_KEY && (ev.key == JK_SPACE || ev.key == JK_ENTER))
1821                    {
1822                        set_state(RUN_STATE);
1823                    }
1824                } break;
1825                case RUN_STATE:
1826                {
1827                    if(ev.window == NULL)
1828                    {
1829                        switch (ev.type)
1830                        {
1831                            case EV_KEY:
1832                            {
1833                                switch (ev.key)
1834                                {
1835                                    case 'm':
1836                                    {
1837                                        if(dev & MAP_MODE)
1838                                            dev -= MAP_MODE;
1839                                        else if((player_list && player_list->next) || dev & EDIT_MODE)
1840                                            dev |= MAP_MODE;
1841
1842                                        if(!(dev & MAP_MODE))
1843                                        {
1844                                            if(dev_cont->tbw)
1845                                                dev_cont->toggle_toolbar();
1846                                            edit_mode = ID_DMODE_DRAW;
1847                                        }
1848                                        need_refresh();
1849                                    } break;
1850                                    case 'v':
1851                                    {
1852                                        wm->push_event(new event(DO_VOLUME, NULL));
1853                                    } break;
1854                                    case 'p':
1855                                    {
1856                                        if(!(dev & EDIT_MODE) && (!main_net_cfg ||
1857                                            (main_net_cfg->state != net_configuration::SERVER &&
1858                                            main_net_cfg->state != net_configuration::CLIENT)))
1859                                        {
1860                                            set_state(PAUSE_STATE);
1861                                        }
1862                                    } break;
1863                                    case 'S':
1864                                    {
1865                                        if(start_edit)
1866                                        {
1867                                            wm->push_event(new event(ID_LEVEL_SAVE, NULL));
1868                                        }
1869                                    } break;
1870                                    case JK_TAB:
1871                                    {
1872                                        if(start_edit)
1873                                            toggle_edit_mode();
1874                                        need_refresh();
1875                                    } break;
1876                                    case 'c':
1877                                    {
1878                                        if(chatting_enabled && (!(dev & EDIT_MODE) && chat))
1879                                            chat->toggle();
1880                                    } break;
1881                                    case '9':
1882                                    {
1883                                        dev = dev ^ PERFORMANCE_TEST_MODE;
1884                                        need_refresh();
1885                                    } break;
1886/*                                    case '=':
1887                                    case '+':
1888                                    {
1889                                        if(!dev_cont->need_plus_minus())
1890                                        {
1891                                            if(wm->key_pressed(JK_CTRL_L))
1892                                                grow_views(20);
1893                                            else
1894                                                grow_views(5);
1895                                            draw(state == SCENE_STATE);
1896                                        }
1897                                    } break;
1898                                    case JK_F10:
1899                                    {
1900                                        make_screen_size(311, 160);
1901                                    } break;
1902                                    case '_':
1903                                    case '-' :
1904                                    {
1905                                        if(!dev_cont->need_plus_minus())
1906                                        {
1907                                            if(wm->key_pressed(JK_CTRL_L))
1908                                                grow_views(-20);
1909                                            else
1910                                                grow_views(-5);
1911                                            draw(state == SCENE_STATE);
1912                                        }
1913                                    } break;
1914*/
1915                                }
1916                            } break;
1917                            case EV_RESIZE:
1918                            {
1919                                view *v;
1920                                for(v = first_view; v; v = v->next)  // see if any views need to change size
1921                                {
1922                                    if(v->local_player())
1923                                    {
1924                                        int w = (xres - 10)/(small_render ? 2 : 1);
1925                                        int h = (yres - 10)/(small_render ? 2 : 1);
1926
1927                                        v->suggest.send_view = 1;
1928                                        v->suggest.cx1 = 5;
1929                                        v->suggest.cx2 = 5 + w;
1930                                        v->suggest.cy1 = 5;
1931                                        v->suggest.cy2 = 5 + h;
1932                                        v->suggest.pan_x = v->pan_x;
1933                                        v->suggest.pan_y = v->pan_y;
1934                                        v->suggest.shift_down = v->shift_down;
1935                                        v->suggest.shift_right = v->shift_right;
1936                                    }
1937                                }
1938                                draw();
1939                            } break;
1940                            case EV_REDRAW:
1941                            {
1942                                screen->add_dirty(ev.redraw.x1, ev.redraw.y1,
1943                                    ev.redraw.x2, ev.redraw.y2);
1944                            } break;
1945                            case EV_MESSAGE:
1946                            {
1947                                switch (ev.message.id)
1948                                {
1949                                    case RAISE_SFX:
1950                                    case LOWER_SFX:
1951                                    case RAISE_MUSIC:
1952                                    case LOWER_MUSIC:
1953                                    {
1954                                        if(ev.message.id == RAISE_SFX && sfx_volume != 127)
1955                                            sfx_volume = min(127, sfx_volume + 16);
1956                                        if(ev.message.id == LOWER_SFX && sfx_volume != 0)
1957                                            sfx_volume = max(sfx_volume - 16, 0);
1958                                        if(ev.message.id == RAISE_MUSIC && music_volume != 126)
1959                                        {
1960                                            music_volume = min(music_volume + 16, 127);
1961                                            if(current_song && (sound_avail & MUSIC_INITIALIZED))
1962                                                current_song->set_volume(music_volume);
1963                                        }
1964
1965                                        if(ev.message.id == LOWER_MUSIC && music_volume != 0)
1966                                        {
1967                                            music_volume = max(music_volume - 16, 0);
1968                                            if(current_song && (sound_avail & MUSIC_INITIALIZED))
1969                                                current_song->set_volume(music_volume);
1970                                        }
1971
1972                                        ((button *)ev.message.data)->push();
1973/*                                        volume_window->inm->redraw();
1974                                        draw_value(volume_window->screen, 2, 43,
1975                                                (volume_window->x2()-volume_window->x1()-1), 8, sfx_volume, 127);
1976                                        draw_value(volume_window->screen, 2, 94,
1977                                                (volume_window->x2()-volume_window->x1()-1), 8, music_volume, 127);
1978*/
1979                                        break;
1980                                    }
1981                                }
1982                            }
1983                        }
1984                    }
1985                } break;
1986            }
1987        }
1988    }
1989}
1990
1991
1992void net_send(int force = 0)
1993{
1994  if((!(dev & EDIT_MODE)) || force)
1995  {
1996    if(demo_man.state == demo_manager::PLAYING)
1997    {
1998      base->input_state = INPUT_PROCESSING;
1999    } else
2000    {
2001
2002
2003
2004      if(!player_list->focus)
2005      {
2006    dprintf("Players have not been created\ncall create_players");
2007    exit(0);
2008      }
2009
2010
2011      view *p = player_list;
2012      for(; p; p = p->next)
2013        if(p->local_player())
2014      p->get_input();
2015
2016
2017      base->packet.write_uint8(SCMD_SYNC);
2018      base->packet.write_uint16(make_sync());
2019
2020      if(base->join_list)
2021      base->packet.write_uint8(SCMD_RELOAD);
2022
2023      //      printf("save tick %d, pk size=%d, rand_on=%d, sync=%d\n", current_level->tick_counter(),
2024      //         base->packet.packet_size(), rand_on, make_sync());
2025      send_local_request();
2026    }
2027  }
2028}
2029
2030void net_receive()
2031{
2032  if(!(dev & EDIT_MODE) && current_level)
2033  {
2034    uint8_t buf[PACKET_MAX_SIZE + 1];
2035    int size;
2036
2037    if(demo_man.state == demo_manager::PLAYING)
2038    {
2039      if(!demo_man.get_packet(buf, size))
2040        size = 0;
2041      base->packet.packet_reset();
2042      base->mem_lock = 0;
2043    } else
2044    {
2045      size = get_inputs_from_server(buf);
2046      if(demo_man.state == demo_manager::RECORDING)
2047    demo_man.save_packet(buf, size);
2048    }
2049
2050    process_packet_commands(buf, size);
2051  }
2052}
2053
2054void game::step()
2055{
2056  clear_tmp();
2057  if(current_level)
2058  {
2059    current_level->unactivate_all();
2060    total_active = 0;
2061    for(view *f = first_view; f; f = f->next)
2062    {
2063      if(f->focus)
2064      {
2065    f->update_scroll();
2066    int w, h;
2067
2068    w=(f->cx2 - f->cx1 + 1);
2069    h=(f->cy2 - f->cy1 + 1);
2070        total_active += current_level->add_actives(f->xoff()-w / 4, f->yoff()-h / 4,
2071                         f->xoff()+w + w / 4, f->yoff()+h + h / 4);
2072      }
2073    }
2074  }
2075
2076  if(state == RUN_STATE)
2077  {
2078    if((dev & EDIT_MODE) || (main_net_cfg && (main_net_cfg->state == net_configuration::CLIENT ||
2079                         main_net_cfg->state == net_configuration::SERVER)))
2080      idle_ticks = 0;
2081
2082    if(demo_man.current_state()==demo_manager::NORMAL && idle_ticks > 420 && demo_start)
2083    {
2084      idle_ticks = 0;
2085      set_state(MENU_STATE);
2086    }
2087    else if(!(dev & EDIT_MODE))               // if edit mode, then don't step anything
2088    {
2089      if(key_down(JK_ESC))
2090      {
2091    set_state(MENU_STATE);
2092    set_key_down(JK_ESC, 0);
2093      }
2094      ambient_ramp = 0;
2095      view *v;
2096      for(v = first_view; v; v = v->next)
2097        v->update_scroll();
2098
2099      cash.prof_poll_start();
2100      current_level->tick();
2101      sbar.step();
2102    } else
2103      dev_scroll();
2104  } else if(state == JOY_CALB_STATE)
2105  {
2106    event ev;
2107    joy_calb(ev);
2108  } else if(state == MENU_STATE)
2109    main_menu();
2110
2111  if(key_down('x') && (key_down(JK_ALT_L) || key_down(JK_ALT_R)) && confirm_quit()) finished = 1;
2112}
2113
2114extern void *current_demo;
2115
2116game::~game()
2117{
2118  current_demo = NULL;
2119  if(first_view == player_list) first_view = NULL;
2120  while(player_list)
2121  {
2122    view *p = player_list;
2123    game_object *o = p->focus;
2124    player_list = player_list->next;
2125    delete p;
2126    o->set_controller(NULL);
2127    if(current_level && o)
2128      current_level->delete_object(o);
2129    else delete o;
2130  }
2131
2132  if(current_level) { delete current_level; current_level = NULL; }
2133
2134  if(first_view != player_list)
2135  {
2136    while(player_list)
2137    {
2138      view *p = player_list;
2139      player_list = player_list->next;
2140      delete p;
2141    }
2142  }
2143
2144  while(first_view)
2145  {
2146    view *p = first_view;
2147    first_view = first_view->next;
2148    delete p;
2149  }
2150
2151  player_list = NULL;
2152
2153  if(old_view)
2154  {
2155    first_view = old_view;
2156    while(first_view)
2157    {
2158      view *p = first_view;
2159      first_view = first_view->next;
2160      delete p;
2161    }
2162  }
2163  old_view = NULL;
2164
2165  int i = 0;
2166  for(; i < total_objects; i++)
2167  {
2168    jfree(object_names[i]);
2169    delete figures[i];
2170  }
2171  free_pframes();
2172  if(fps_mark_start) delete fps_mark_start; fps_mark_start = NULL;
2173  delete pal;
2174  jfree(object_names);
2175  jfree(figures);
2176
2177  jfree(backtiles);
2178  jfree(foretiles);
2179  if(total_weapons)
2180    jfree(weapon_types);
2181
2182  config_cleanup();
2183  delete color_table;
2184  delete wm;
2185  delete game_font;
2186  delete big_font;
2187  delete console_font;
2188  if(total_help_screens)
2189    jfree(help_screens);
2190
2191  close_graphics();
2192  image_uninit();
2193}
2194
2195
2196
2197void game::draw(int scene_mode)
2198{
2199    screen->add_dirty(0, 0, xres, yres);
2200//    image *bt = cash.img(border_tile);
2201//    int tw = bt->width(), th = bt->height();
2202  screen->clear();
2203//  for(y = 0; y < yt; y++, dy += th)
2204//    for(x = 0, dx = 0; x < xt; x++, dx += tw)
2205//      bt->put_image(screen, dx, dy);
2206
2207    if(scene_mode)
2208    {
2209        char const *helpstr = "ARROW KEYS CHANGE TEXT SPEED";
2210        wm->font()->put_string(screen, screen->width()/2-(wm->font()->width()*strlen(helpstr))/2 + 1,
2211            screen->height()-wm->font()->height()-5 + 1, helpstr, wm->dark_color());
2212        wm->font()->put_string(screen, screen->width()/2-(wm->font()->width()*strlen(helpstr))/2,
2213            screen->height()-wm->font()->height()-5, helpstr, wm->bright_color());
2214    }
2215/*    else
2216    {
2217        char *helpstr="PRESS h FOR HELP";
2218        wm->font()->put_string(screen, screen->width()-wm->font()->width()*strlen(helpstr)-5,
2219            screen->height()-wm->font()->height()-5, helpstr);
2220    }*/
2221/*    int dc = cash.img(window_colors)->pixel(0, 2);
2222    int mc = cash.img(window_colors)->pixel(1, 2);
2223    int bc = cash.img(window_colors)->pixel(2, 2);
2224    screen->line(0, 0, screen->width()-1, 0, dc);
2225    screen->line(0, 0, 0, screen->height()-1, dc);
2226    screen->line(0, screen->height()-1, screen->width()-1, screen->height()-1, bc);
2227    screen->line(screen->width()-1, 0, screen->width()-1, screen->height()-1, bc); */
2228
2229    for(view *f = first_view; f; f = f->next)
2230        draw_map(f, 0);
2231
2232    sbar.redraw(screen);
2233}
2234
2235int external_print = 0;
2236
2237void start_sound(int argc, char **argv)
2238{
2239  sfx_volume = music_volume = 127;
2240
2241  for(int i = 1; i < argc; i++)
2242    if(!strcmp(argv[i], "-sfx_volume"))
2243    {
2244      i++;
2245      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2246        sfx_volume = atoi(argv[i]);
2247      else printf("Bad sound effects volume level, use 0..127\n");
2248    }
2249    else if(!strcmp(argv[i], "-music_volume"))
2250    {
2251      i++;
2252      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2253        music_volume = atoi(argv[i]);
2254      else printf("Bad music volume level, use 0..127\n");
2255    }
2256
2257  sound_avail = sound_init(argc, argv);
2258}
2259
2260void game_printer(char *st)
2261{
2262  if(dev_console && !external_print)
2263  {
2264    dev_console->put_string(st);
2265  }
2266  else fprintf(stderr, "%s", st);
2267}
2268
2269
2270void game_getter(char *st, int max)
2271{
2272  if(!max) return;
2273  max--;
2274  *st = 0;
2275  if(dev_console && !external_print)
2276  {
2277    dev_console->show();
2278    int t = 0;
2279    event ev;
2280    do
2281    {
2282      get_event(ev);
2283      if(ev.type == EV_KEY)
2284      {
2285    if(ev.key == JK_BACKSPACE)
2286    {
2287      if(t)
2288      {
2289        dev_console->print_f("%c", ev.key);
2290        t--;
2291        st--;
2292        *st = 0;
2293        max++;
2294      }
2295    } else if(ev.key>=' ' && ev.key<='~')
2296    {
2297      dev_console->print_f("%c", ev.key);
2298      *st = ev.key;
2299      t++;
2300      max--;
2301      st++;
2302      *st = 0;
2303    }
2304      }
2305      wm->flush_screen();
2306    } while(ev.type != EV_KEY || ev.key != JK_ENTER);
2307    dprintf("\n");
2308  }
2309  else
2310  {
2311    if(fgets(st, max, stdin))
2312    {
2313      if(*st)
2314        st[strlen(st)-1]=0;
2315    }
2316  }
2317}
2318
2319
2320void show_startup()
2321{
2322    dprintf("Abuse version %s\n", PACKAGE_VERSION);
2323}
2324
2325char *get_line(int open_braces)
2326{
2327  char *line=(char *)jmalloc(1000, "lstring");
2328  fgets(line, 1000, stdin);
2329
2330  char prev=' ';
2331  for(char *s = line; *s && (prev!=' ' || *s!=';'); s++)
2332  {
2333    prev=*s;
2334    if(*s=='(') open_braces++;
2335    else if(*s==')') open_braces--;
2336  }
2337  if(open_braces < 0)
2338    fprintf(stderr, "\nToo many)'s\n");
2339  else if(open_braces > 0)
2340  {
2341    char *s2 = get_line(open_braces);
2342    line=(char *)jrealloc(line, strlen(line)+strlen(s2)+1, "lstring");
2343    strcat(line, s2);
2344    jfree(s2);
2345  }
2346  return line;
2347}
2348
2349void check_for_upgrade(int argc, char **argv)
2350{
2351  for(int i = 1; i < argc; i++)
2352    if(!strcmp(argv[i], "-upgrade"))
2353    {
2354      lisp_init(0xf000, 0x30000);
2355      char const *prog="(load \"lisp/upgrade.lsp\")";
2356      char const *cs = prog;
2357      if(!eval(compile(cs)))
2358    printf("file \"lisp/upgrade.lsp\" does not exist, cannot upgrade\n");
2359
2360      exit(0);
2361    }
2362}
2363
2364void check_for_lisp(int argc, char **argv)
2365{
2366    for(int i = 1; i < argc; i++)
2367    {
2368        if(!strcmp(argv[i], "-lisp"))
2369        {
2370            lisp_init(0xf000, 0x30000);
2371            char const *eof_char = "Ctrl-D";
2372            fprintf(stderr,
2373                    " CLIVE (C) 1995 Jonathan Clark, all rights reserved\n"
2374                    "   (C LISP interpreter and various extentions)\n"
2375                    "Type (%s) to exit\n", eof_char);
2376
2377            while(!feof(stdin))
2378            {
2379                fprintf(stderr, "Lisp> ");
2380                char *l = get_line(0);
2381                char const *s = l;
2382                while(*s)
2383                {
2384                    void *prog = compile(s);
2385                    l_user_stack.push(prog);
2386                    while(*s==' ' || *s=='\t' || *s=='\r' || *s=='\n') s++;
2387                    lprint(eval(prog));
2388                    l_user_stack.pop(1);
2389                }
2390                jfree(l);
2391            }
2392            fprintf(stderr, "End of input : bye\n");
2393            exit(0);
2394        }
2395    }
2396}
2397
2398
2399void music_check()
2400{
2401  if(sound_avail & MUSIC_INITIALIZED)
2402  {
2403    if(current_song && !current_song->playing())
2404    {
2405      current_song->play();
2406      dprintf("song finished\n");
2407    }
2408    if(!current_song)
2409    {
2410
2411      current_song = new song("music/intro.hmi");
2412      current_song->play(music_volume);
2413
2414/*      if(DEFINEDP(symbol_function(l_next_song)))  // if user function installed, call it to load up next song
2415      {
2416    int sp = current_space;
2417    current_space = PERM_SPACE;
2418    eval_function((lisp_symbol *)l_next_song, NULL);
2419    current_space = sp;
2420      } */
2421    }
2422  }
2423}
2424
2425void setup(int argc, char **argv);
2426
2427void share_end();
2428void show_end();
2429
2430void show_sell(int abortable);
2431
2432extern pmenu *dev_menu;
2433
2434
2435extern int jmalloc_max_size;
2436extern int jmalloc_min_low_size;
2437
2438void game_net_init(int argc, char **argv)
2439{
2440  int nonet=!net_init(argc, argv);
2441  if(nonet)
2442    dprintf("No network driver, or network driver returned failure\n");
2443  else
2444  {
2445    set_file_opener(open_nfs_file);
2446    if(main_net_cfg && main_net_cfg->state == net_configuration::CLIENT)
2447    {
2448      if(set_file_server(net_server))
2449      start_running = 1;
2450      else
2451      {
2452                dprintf("Unable to attach to server, quitting\n");
2453                exit(0);
2454      }
2455    } else
2456    {
2457      int i;
2458      for(i = 1; i < argc - 1; i++)
2459      if(!strcmp(argv[i], "-fs"))
2460      if(!set_file_server(argv[i + 1]))
2461      dprintf("could not set default file server to %s\n", argv[i + 1]);
2462    }
2463  }
2464
2465}
2466
2467#if(defined(__APPLE__) && !defined(__MACH__))
2468extern int PixMult;
2469#if 1
2470char cmdline[256];
2471#elif 1
2472char cmdline[] = "";
2473#elif 1
2474char cmdline[] = "abuse -server -a deathmat";
2475#else
2476char cmdline[] = "abuse -net 193.246.40.9";
2477#endif
2478char delims[] = " ";
2479char *tmp_argv[255];
2480
2481void GetArgs(int &argc, char **(&argv))
2482{
2483    char *s;
2484
2485    printf("Usage:\n"
2486                    "  abuse [-options]\n\n"
2487                    "  Options:\n"
2488                    "    -server -a deathmat        become a server for deathmatch game\n"
2489                    "    -net <dotted ip address>   connect to a server\n\n"
2490                    "Options for mac:\n"
2491                    "  Hold down <control> for single pixel mode\n"
2492                    "  Hold down <option> for edit mode\n"
2493                    "  Hold down <left shift> for double size mode\n\n"
2494                    "If started with no command line options, networking will attempt\n"
2495                    "  to search the local network for servers\n\n"
2496);
2497    printf("Enter command line:\n");
2498    gets(cmdline);
2499
2500    argc = 0;
2501    argv = tmp_argv;
2502    s = strtok(cmdline, delims);
2503    while(s)
2504    {
2505        argv[argc] = s;
2506        argc++;
2507        s = strtok(0, delims);
2508    }
2509    argv[argc] = 0;
2510}
2511
2512#endif
2513
2514int main(int argc, char **argv)
2515{
2516#if(defined(__APPLE__) && !defined(__MACH__))
2517    GetArgs(argc, argv);
2518#endif
2519
2520    start_argc = argc;
2521    start_argv = argv;
2522
2523    for(int i = 0; i < argc; i++)
2524    {
2525        if(!strcmp(argv[i], "-cprint"))
2526        {
2527            external_print = 1;
2528        }
2529
2530        if(!strcmp(argv[i], "-min_low"))
2531        {
2532            i++;
2533            jmalloc_min_low_size = atoi(argv[i]);
2534        }
2535    }
2536
2537//  jmalloc_max_size = 0x150000;
2538    jmalloc_init(0x150000);
2539//  jmalloc_init(100000);
2540
2541#if(defined(__APPLE__) && !defined(__MACH__))
2542    unsigned char km[16];
2543
2544    fprintf(stderr, "Mac Options: ");
2545    xres = 320; yres = 200;
2546    GetKeys((uint32_t*)&km);
2547    if((km[ 0x3a >>3] >> (0x3a & 7)) &1 != 0)
2548    {
2549        dev|=EDIT_MODE;
2550        start_edit = 1;
2551        start_running = 1;
2552        disable_autolight = 1;
2553        fprintf(stderr, "Edit Mode...");
2554    }
2555    if((km[ 0x3b >>3] >> (0x3b & 7)) &1 != 0)
2556    {
2557        PixMult = 1;
2558        fprintf(stderr, "Single Pixel...");
2559    }
2560    else
2561    {
2562        PixMult = 2;
2563        fprintf(stderr, "Double Pixel...");
2564    }
2565    if((km[ 0x38 >>3] >> (0x38 & 7)) &1 != 0)
2566    {
2567        xres *= 2;  yres *= 2;
2568        fprintf(stderr, "Double Size...");
2569    }
2570    fprintf(stderr, "\n");
2571
2572    if(tcpip.installed())
2573        fprintf(stderr, "Using %s\n", tcpip.name());
2574#endif
2575
2576    set_dprinter(game_printer);
2577    set_dgetter(game_getter);
2578    set_no_space_handler(handle_no_space);
2579
2580    setup(argc, argv);
2581
2582    show_startup();
2583
2584    start_sound(argc, argv);
2585
2586    stat_man = new text_status_manager();
2587    if(!get_option("-no_timer"))
2588    {
2589        timer_init();
2590    }
2591
2592    // look to see if we are supposed to fetch the data elsewhere
2593    if(getenv("ABUSE_PATH"))
2594    {
2595        set_filename_prefix(getenv("ABUSE_PATH"));
2596    }
2597
2598    // look to see if we are supposed to save the data elsewhere
2599    if(getenv("ABUSE_SAVE_PATH"))
2600    {
2601        set_save_filename_prefix(getenv("ABUSE_SAVE_PATH"));
2602    }
2603
2604    jrand_init();
2605    jrand();        // so compiler doesn't complain
2606
2607    set_spec_main_file("abuse.spe");
2608
2609    check_for_lisp(argc, argv);
2610    check_for_upgrade(argc, argv);
2611
2612    do
2613    {
2614        if(main_net_cfg)
2615        {
2616            if(!main_net_cfg->notify_reset())
2617            {
2618                if(!get_option("-no_timer"))
2619                    timer_uninit();
2620                sound_uninit();
2621                exit(0);
2622            }
2623        }
2624
2625        game_net_init(argc, argv);
2626        lisp_init(0x16000, 0x94000);
2627//        lisp_init(0x100000, 0x10000);
2628
2629        dev_init(argc, argv);
2630
2631        game *g = new game(argc, argv);
2632
2633        dev_cont = new dev_controll();
2634        dev_cont->load_stuff();
2635
2636        g->get_input();        // prime the net
2637
2638        int xx;
2639        for(xx = 1; xx < argc; xx++)
2640        {
2641            if(!strcmp(argv[xx], "-server"))
2642            {
2643                xx++;
2644                if(!become_server(argv[xx]))
2645                {
2646                    dprintf("unable to become a server\n");
2647                    exit(0);
2648                }
2649                xx = argc + 1;
2650            }
2651        }
2652
2653        if(main_net_cfg)
2654        {
2655            wait_min_players();
2656        }
2657
2658        net_send(1);
2659        if(net_start())
2660        {
2661            g->step();                // process all the objects in the
2662            g->calc_speed();
2663            g->update_screen();        // redraw the screen with any changes
2664        }
2665
2666    while(!g->done())
2667    {
2668      music_check();
2669
2670      if(req_end)
2671      {
2672                delete current_level;
2673                current_level = NULL;
2674
2675                show_end();
2676
2677                the_game->set_state(MENU_STATE);
2678                req_end = 0;
2679      }
2680
2681      if(demo_man.current_state()==demo_manager::NORMAL)
2682      {
2683                net_receive();
2684      }
2685
2686      if(req_name[0])            // see if a request for a level load was made during the last tick
2687      {
2688        g->load_level(req_name);
2689        req_name[0]=0;
2690        g->draw(g->state == SCENE_STATE);
2691      }
2692
2693      //    if(demo_man.current_state()!=demo_manager::PLAYING)
2694      g->get_input();
2695
2696      if(demo_man.current_state()==demo_manager::NORMAL)
2697      net_send();
2698      else demo_man.do_inputs();
2699
2700      service_net_request();
2701
2702      g->step();                        // process all the objects in the
2703
2704      server_check();
2705
2706      g->calc_speed();
2707      if(!req_name[0])                // see if a request for a level load was made during the last tick
2708        g->update_screen();               // redraw the screen with any changes
2709
2710
2711    }
2712
2713    net_uninit();
2714
2715    if(net_crcs)
2716    {
2717      net_crcs->clean_up();
2718      delete net_crcs;
2719      net_crcs = NULL;
2720    }
2721
2722    delete chat;
2723
2724    milli_wait(500);
2725
2726    if(small_render) { delete small_render; small_render = NULL; }
2727
2728    if(current_song)
2729    { current_song->stop();
2730      delete current_song;
2731      current_song = NULL;
2732    }
2733
2734
2735    cash.empty();
2736
2737
2738    if(dev_console)
2739    {
2740      delete dev_console;
2741      dev_console = NULL;
2742    }
2743
2744    if(dev_menu)
2745    {
2746      delete dev_menu;
2747      dev_menu = NULL;
2748    }
2749
2750    delete g;
2751    if(old_pal) delete old_pal; old_pal = NULL;
2752    compiled_uninit();
2753    delete_all_lights();
2754    jfree(white_light_initial);
2755
2756    for(int i = 0; i < TTINTS; i++) jfree(tints[i]);
2757
2758
2759    dev_cleanup();
2760    delete dev_cont; dev_cont = NULL;
2761    delete stat_man;
2762    stat_man = new text_status_manager();
2763
2764    if(!(main_net_cfg && main_net_cfg->restart_state()))
2765    {
2766      void *end_msg = make_find_symbol("end_msg");
2767      if(DEFINEDP(symbol_value(end_msg)))
2768      printf("%s\n", lstring_value(symbol_value(end_msg)));
2769    }
2770
2771    lisp_uninit();
2772
2773    base->packet.packet_reset();
2774    mem_report("end.mem");
2775  } while(main_net_cfg && main_net_cfg->restart_state());
2776
2777    delete stat_man;
2778
2779    if(main_net_cfg)
2780    {
2781        delete main_net_cfg;
2782        main_net_cfg = NULL;
2783    }
2784    set_filename_prefix(NULL);  // dealloc this mem if there was any
2785    set_save_filename_prefix(NULL);
2786
2787    if(!get_option("-no_timer"))
2788    {
2789        timer_uninit();
2790    }
2791
2792// AK -> Commented this out to stop a crash as the file prefix has already
2793//       been released.  Need to fix this.
2794//    mem_report("end.mem");
2795
2796//    jmalloc_uninit();
2797    l_user_stack.clean_up();
2798    l_ptr_stack.clean_up();
2799
2800    sound_uninit();
2801
2802    exit(0);
2803
2804    return 0;
2805}
2806
Note: See TracBrowser for help on using the repository browser.