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

Last change on this file since 106 was 106, checked in by Sam Hocevar, 15 years ago
  • Rename the "eh" variable to "wm" because it's a window manager, not an event handler.
  • No longer pass the window manager to functions, there's only one.

Inspired by Win32 Abuse changelog for January 28, 2001:

  • Starting work on singleton code; will get rid of all

references to an arbitrary window_manager* because
there's only going to be one, and it's not ever
going to change.

File size: 73.3 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(WINDOW_FRAME_LEFT, WINDOW_FRAME_TOP +
110                                       wm->font()->height() * 2, ID_NULL,
111                                     no_space_msg, NULL);
112    button *b = new button(WINDOW_FRAME_LEFT, WINDOW_FRAME_TOP,
113                           ID_QUIT_OK, "Quit", inf);
114    jwindow *no_space = wm->new_window(0, 0, -1, -1, b, "ERROR");
115
116    event ev;
117    do
118    {
119        wm->flush_screen();
120        wm->get_event(ev);
121    } while(ev.type != EV_MESSAGE || ev.message.id != ID_QUIT_OK);
122    wm->close_window(no_space);
123
124    close_graphics();
125    exit(1);
126}
127
128void game::play_sound(int id, int vol, int32_t x, int32_t y)
129{
130    if(!(sound_avail & SFX_INITIALIZED))
131        return;
132    if(vol < 15)
133        return;
134    if(!player_list)
135        return;
136
137    uint32_t mdist = 0xffffffff;
138    view *cd = NULL;
139    for(view *f = player_list; f; f = f->next)
140    {
141        if(f->local_player())
142        {
143            int32_t cx = abs(f->x_center()-x), cy = abs(f->y_center()-y), d;
144            if(cx < cy)
145                d = cx + cy - (cx >> 1);
146            else
147                d = cx + cy - (cy >> 1);
148
149            if((unsigned)d < mdist)
150            {
151                cd = f;
152                mdist = d;
153            }
154        }
155    }
156    if(mdist > 500 || !cd)
157        return;
158    if(mdist < 100)
159        mdist = 0;
160    else
161        mdist -= 100;
162
163    int v = (400 - mdist) * sfx_volume / 400 - (127 - vol);
164
165    // Calculate the position of the sound relative to the player
166    int p = cd->x_center() - x;
167    if(p > 0)
168        p = (int)(((double)p / 255.0) * 128.0);
169    else
170        p = (int)(((double)abs(p) / 255.0) * -128.0);
171    p += 128;
172    if(p < 0) p = 0;
173    if(p > 255) p = 255;
174
175    if(v > 0)
176        cash.sfx(id)->play(v, 128, p);
177}
178
179int get_option(char const *name)
180{
181    int i;
182    for(i = 1; i < start_argc; i++)
183    {
184        if(!strcmp(start_argv[i], name))
185        {
186            return i;
187        }
188    }
189    return 0;
190}
191
192
193void make_screen_size(int w, int h)
194{
195    for(view *f = player_list; f; f = f->next)
196    {
197        if(!f->local_player())
198            continue;
199
200        if((unsigned)w >= xres - 1)
201            w = xres - 2;
202        if((unsigned)h >= yres - 1)
203            h = yres - 2;
204        f->suggest.cx1 = (xres + 1) / 2 - w / 2;
205        f->suggest.cx2 = (xres + 1) / 2 + w / 2;
206        f->suggest.cy1 = (yres - 31) / 2 + 5 - h / 2;
207        f->suggest.cy2 = (yres - 51) / 2 + 5 + h / 2;
208        f->suggest.shift_down = f->shift_down;
209        f->suggest.shift_right = f->shift_right;
210        f->suggest.pan_x = f->pan_x;
211        f->suggest.pan_y = f->pan_y;
212        f->suggest.send_view = 1;
213    }
214}
215
216void game::grow_views(int amount)
217{
218    view *f;
219
220    for(f = first_view; f; f = f->next)
221    {
222        if(!f->local_player())
223            continue;
224
225        f->suggest.cx1=(f->cx1 - amount);
226        f->suggest.cy1 = f->cy1 - amount / 2;
227        f->suggest.cx2=(f->cx2 + amount);
228        f->suggest.cy2 = f->cy2 + amount / 2;
229        f->suggest.shift_down = f->shift_down;
230        f->suggest.shift_right = f->shift_right;
231        f->suggest.pan_x = f->pan_x;
232        f->suggest.pan_y = f->pan_y;
233
234        f->suggest.send_view = 1;
235    }
236
237    for(f = first_view; f; f = f->next)
238    {
239        if(!f->local_player())
240            continue;
241
242        if(f->suggest.cx2 - f->suggest.cx1 < 20
243           || f->suggest.cy2 - f->suggest.cy1 < 15
244           || f->suggest.cx1 < 0 || f->suggest.cy1 < 0)
245            f->suggest.send_view = 0;
246
247        if(f->next && f->next->local_player()
248           && f->suggest.cy2 >= f->next->cy1)
249            f->suggest.send_view = 0;
250    }
251}
252
253void game::pan(int xv, int yv)
254{
255    first_view->pan_x += xv;
256    first_view->pan_y += yv;
257}
258
259view *game::view_in(int mousex, int mousey)
260{
261    for(view *f = first_view; f; f = f->next)
262        if(f->drawable() && mousex >= f->cx1 && mousey >= f->cy1
263           && mousex <= f->cx2 && mousey <= f->cy2)
264            return f;
265    return NULL;
266}
267
268int playing_state(int state)
269{
270    return state == RUN_STATE || state == PAUSE_STATE;
271}
272
273void game::ftile_on(int screenx, int screeny, int32_t &x, int32_t &y)
274{
275    mouse_to_game(screenx, screeny, x, y);
276    x /= ftile_width();
277    y /= ftile_height();
278}
279
280void game::btile_on(int screenx, int screeny, int32_t &x, int32_t &y)
281{
282    view *f = view_in(screenx, screeny);
283    if(f)
284    {
285        x = ((int32_t)screenx - (int32_t)f->cx1
286                + f->xoff() * bg_xmul / bg_xdiv) / (int32_t)b_wid;
287        y = ((int32_t)screeny - (int32_t)f->cy1
288                + f->yoff() * bg_ymul / bg_ydiv) / (int32_t)b_hi;
289    }
290    else
291    {
292        x = -1;
293        y = -1;
294    }
295}
296
297void game::mouse_to_game(int32_t x, int32_t y,
298                         int32_t &gamex, int32_t &gamey, view *f)
299{
300    if(!f)
301        f = view_in(x, y);
302    if(!f)
303        f = player_list;  // if not in a view use the first one
304
305    if(f)
306    {
307        if(dev & MAP_MODE)
308        {
309            gamex = (x - (int32_t)f->cx1) * ftile_width() / AUTOTILE_WIDTH + map_xoff * ftile_width();
310            gamey = (y - (int32_t)f->cy1) * ftile_height() / AUTOTILE_HEIGHT + map_yoff * ftile_height();
311        }
312        else
313        {
314            gamex = x - (int32_t)f->cx1 + f->xoff();
315            gamey = y - (int32_t)f->cy1 + f->yoff();
316        }
317    }
318}
319
320void game::game_to_mouse(int32_t gamex, int32_t gamey, view *which,
321                         int32_t &x, int32_t &y)
322{
323    if(!(dev & MAP_MODE))
324    {
325        x = gamex - which->xoff() + which->cx1;
326        y = gamey - which->yoff() + which->cy1;
327        return;
328    }
329
330    int32_t x1, y1;
331
332    if(dev & EDIT_MODE)
333    {
334        x1 = map_xoff;
335        y1 = map_yoff;
336    }
337    else
338    {
339        if(which->focus)
340        {
341            x1 = which->focus->x / ftile_width()
342                  - (which->cx2 - which->cx1) / AUTOTILE_WIDTH / 2;
343            y1 = which->focus->y / ftile_height()
344                  - (which->cy2 - which->cy1) / AUTOTILE_HEIGHT / 2;
345        }
346        else
347            x1 = y1 = 0;
348    }
349
350    if(x1 < 0)
351        x1 = 0;
352    if(y1 < 0)
353        y1 = 0;
354
355    x = gamex * AUTOTILE_WIDTH / ftile_width()
356          - x1 * AUTOTILE_WIDTH + which->cx1;
357    if(x1 > 0)
358        x -= (which->focus->x * AUTOTILE_WIDTH / ftile_width())
359               % AUTOTILE_WIDTH;
360
361    y = gamey * AUTOTILE_HEIGHT / ftile_height()
362          - y1 * AUTOTILE_HEIGHT + which->cy1;
363    if(y1 > 0)
364        y -= (which->focus->y * AUTOTILE_HEIGHT / ftile_height())
365               % AUTOTILE_HEIGHT;
366}
367
368int window_state(int state)
369{
370    switch (state)
371    {
372    case RUN_STATE:
373    case PAUSE_STATE:
374    case JOY_CALB_STATE:
375        return 1;
376
377    case INTRO_START_STATE:
378    case HELP_STATE:
379    case INTRO_MORPH_STATE:
380    case MENU_STATE:
381    case SCENE_STATE:
382        return 0;
383    }
384
385    return 1;
386}
387
388void game::set_state(int new_state)
389{
390    int d = 0;
391    reset_keymap(); // we think all the keys are up right now
392
393    if(playing_state(new_state) && !playing_state(state))
394    {
395        if(first_view && first_view != player_list)
396        {
397            while(first_view)
398            {
399                view *tmp = first_view;
400                first_view = first_view->next;
401                delete tmp;
402            }
403            first_view = old_view;
404            old_view = NULL;
405        }
406        first_view = player_list;
407        d = 1;
408    }
409    else if(!playing_state(new_state) && (playing_state(state) || state == START_STATE))
410    {
411        if(player_list)
412        {
413            first_view = new view(player_list->focus, NULL, -1);
414            first_view->pan_x = player_list->xoff();
415            first_view->pan_y = player_list->yoff();
416        }
417        else
418            first_view = new view(NULL, NULL, 0);
419        first_view->cx1 = (xres + 1) / 2 - 155;
420        first_view->cy1 = (yres + 1) / 2 - 95;
421        first_view->cx2 = (xres + 1) / 2 + 155;
422        if(total_weapons)
423            first_view->cy2 = (yres + 1) / 2 + 68;
424        else
425            first_view->cy2 = (yres + 1) / 2 + 95;
426        d = 1;
427    }
428
429    // switching to / from scene mode cause the screen size to change and the border to change
430    // so we need to redraw.
431    if(window_state(new_state) && !window_state(state))
432        wm->show_windows();
433    else if(!window_state(new_state) && window_state(state))
434        wm->hide_windows();
435
436    int old_state = state;
437    state = new_state;
438
439    pal->load();    // restore old palette
440
441    if(playing_state(state) &&  !(dev & EDIT_MODE))
442        wm->set_mouse_shape(cash.img(c_target)->copy(), 8, 8);
443    else
444        wm->set_mouse_shape(cash.img(c_normal)->copy(), 1, 1);
445
446    if(old_state == SCENE_STATE && new_state != SCENE_STATE)
447    {
448        d = 1;
449        scene_director.set_abort(0);   // don't skip any more scene stuff
450    }
451    else if(new_state == SCENE_STATE && old_state != SCENE_STATE)
452        d = 1;
453
454    if(d)
455        draw(state == SCENE_STATE);
456
457    dev_cont->set_state(new_state);
458}
459
460void game::joy_calb(event &ev)
461{
462    if(!joy_win) // make sure the joy stick calibration window is open
463        return;
464
465    if(ev.type == EV_SPURIOUS) // spurious means we should update your status
466    {
467        int b1, b2, b3 = 0, x, y;
468        joy_status(b1, b2, b2, x, y);
469        int but = b1|b2|b3;
470        if(x > 0) x = 1; else if(x < 0) x = -1;
471        if(y > 0) y = 1; else if(y < 0) y = -1;
472        if(but) but = 1;
473        int dx = WINDOW_FRAME_LEFT + 20, dy = WINDOW_FRAME_TOP + 5;
474        image *jim = cash.img(joy_picts[but * 9+(y + 1)*3 + x + 1]);
475        joy_win->screen->bar(dx, dy, dx + jim->width()+6, dy + jim->height()+6, wm->black());
476        jim->put_image(joy_win->screen, dx + 3, dy + 3);
477
478        if(but)
479            joy_calibrate();
480    }
481    else if(ev.type == EV_MESSAGE && ev.message.id == JOY_OK)
482    {
483        wm->close_window(joy_win);
484        joy_win = NULL;
485        set_state(MENU_STATE);
486    }
487}
488
489void game::menu_select(event &ev)
490{
491    state = DEV_MOUSE_RELEASE;
492    if(top_menu)
493    {
494#if 0
495        wm->push_event(new event(men_mess[((pick_list *)ev.message.data)->get_selection()], NULL));
496        wm->close_window(top_menu);
497        top_menu = NULL;
498#endif
499    }
500}
501
502
503void game::show_help(char const *st)
504{
505    strcpy(help_text, st);
506    help_text_frames = 0;
507    refresh = 1;
508}
509
510void game::draw_value(image *screen, int x, int y, int w, int h,
511                      int val, int max)
512{
513    screen->bar(x, y, x + w - 1, y + h, wm->dark_color());
514    screen->bar(x, y + 1, x + w * val / max, y + h - 1, wm->bright_color());
515}
516
517
518void game::set_level(level *nl)
519{
520    if(current_level)
521        delete current_level;
522    current_level = nl;
523}
524
525void game::load_level(char const *name)
526{
527    if(current_level)
528      delete current_level;
529
530    bFILE *fp = open_file(name, "rb");
531
532    if(fp->open_failure())
533    {
534        delete fp;
535        current_level = new level(100, 100, name);
536        char msg[100];
537        sprintf(msg, symbol_str("no_file"), name);
538        show_help(msg);
539    }
540    else
541    {
542        spec_directory sd(fp);
543        current_level = new level(&sd, fp, name);
544        delete fp;
545    }
546
547    base->current_tick=(current_level->tick_counter()&0xff);
548
549    current_level->level_loaded_notify();
550    the_game->help_text_frames = 0;
551}
552
553int game::done()
554{
555  return finished || (main_net_cfg && main_net_cfg->restart_state());
556
557}
558
559void game::end_session()
560{
561  finished = 1;
562  if(main_net_cfg)
563  {
564    delete main_net_cfg;
565    main_net_cfg = NULL;
566  }
567}
568
569void game::put_block_fg(int x, int y, trans_image *im)
570{
571  for(view *f = first_view; f; f = f->next)
572  {
573    if(f->drawable())
574    {
575      int xoff = f->xoff(), yoff = f->yoff(), viewx1 = f->cx1, viewy1 = f->cy1, viewx2 = f->cx2, viewy2 = f->cy2;
576      if(xoff / ftile_width()>x || xoff / ftile_width()+(viewx2 - viewx1)/ftile_width()+1 < x ||
577      yoff / ftile_height()>y || yoff / ftile_height()+(viewy2 - viewy1)/ftile_height()+1 < y) return;
578      short cx1, cy1, cx2, cy2;
579      screen->get_clip(cx1, cy1, cx2, cy2);
580      screen->set_clip(viewx1, viewy1, viewx2, viewy2);
581      im->put_image(screen, (x - xoff / ftile_width())*ftile_width()+viewx1 - xoff % ftile_width(),
582            (y - yoff / ftile_height())*ftile_height()+viewy1 - yoff % ftile_height());
583      screen->set_clip(cx1, cy1, cx2, cy2);
584    }
585  }
586}
587
588void game::put_block_bg(int x, int y, image *im)
589{
590  for(view *f = first_view; f; f = f->next)
591  {
592    if(f->drawable())
593    {
594      int xoff = f->xoff(), yoff = f->yoff(), viewx1 = f->cx1, viewy1 = f->cy1, viewx2 = f->cx2, viewy2 = f->cy2;
595      int xo = xoff * bg_xmul / bg_xdiv;
596      int yo = yoff * bg_ymul / bg_ydiv;
597
598      if(xo / btile_width()>x || xo / btile_width()+(viewx2 - viewx1)/btile_width()+1 < x ||
599      yo / btile_height()>y || yo / btile_height()+(viewy2 - viewy1)/btile_height()+1 < y) return;
600      short cx1, cy1, cx2, cy2;
601      screen->get_clip(cx1, cy1, cx2, cy2);
602      screen->set_clip(viewx1, viewy1, viewx2, viewy2);
603      im->put_image(screen, (x - xo / btile_width())*btile_width()+viewx1 - xo % btile_width(),
604            (y - yo / btile_height())*btile_height()+viewy1 - yo % btile_height(), 0);
605      screen->set_clip(cx1, cy1, cx2, cy2);
606    }
607  }
608}
609
610int need_delay = 1;
611
612void game::dev_scroll()
613{
614  need_delay = 0;
615  if(dev)
616  {
617    int xmargin, ymargin;
618    if(xres > 400)
619    {
620      xmargin = 20;
621      ymargin = 10;
622    }
623    else
624    {
625      xmargin = 10;
626      ymargin = 5;
627    }
628
629    int xs, ys;
630    if(mousex < xmargin &&  dev_cont->ok_to_scroll()) xs = -18;
631    else if(mousex>(screen->width()-xmargin) &&  dev_cont->ok_to_scroll()) xs = 18;
632    else if(wm->key_pressed(JK_LEFT) && !last_input && !dev_cont->need_arrows())
633      xs = -18;
634    else if(wm->key_pressed(JK_RIGHT) && !last_input && !dev_cont->need_arrows())
635      xs = 18;
636    else xs = 0;
637
638
639    if(mousey < ymargin && dev_cont->ok_to_scroll()) ys = -18;
640    else if(mousey>(screen->height()-ymargin) &&  dev_cont->ok_to_scroll()) ys = 18;
641    else if(wm->key_pressed(JK_UP) && !last_input)
642      ys = -18;
643    else if(wm->key_pressed(JK_DOWN) && !last_input)
644      ys = 18;
645    else ys = 0;
646
647
648    if(xs || ys)
649    {
650      need_delay = 1;
651      if(dev & MAP_MODE)
652      {
653    map_xoff += xs / 2;
654    map_yoff += ys / 2;
655    if(map_xoff < 0) map_xoff = 0;
656    if(map_yoff < 0) map_yoff = 0;
657      }
658      else
659      {
660    for(view *v = first_view; v; v = v->next)
661    {
662      if(xs >= 0 || v->xoff()>0)
663        v->pan_x += xs;
664      if(ys >= 0 || v->yoff()>0)
665        v->pan_y += ys;
666    }
667      }
668      refresh = 1;
669    }
670  }
671}
672
673void remap_area(image *screen, int x1, int y1, int x2, int y2, uint8_t *remap)
674{
675  uint8_t *sl=(uint8_t *)screen->scan_line(y1)+x1;
676  int x, y, a = screen->width()-(x2 - x1 + 1);
677  uint8_t c;
678  for(y = y1; y <= y2; y++)
679  {
680    for(x = x1; x <= x2; x++)
681    {
682      c=*sl;
683      *(sl++)=remap[c];
684    }
685    sl += a;
686  }
687}
688
689static void post_render()
690{
691  if(DEFINEDP(symbol_function(l_post_render)))
692  {
693    screen->dirt_off();
694    clear_tmp();
695    eval_function((lisp_symbol *)l_post_render, NULL);
696    clear_tmp();
697    screen->dirt_on();
698  }
699}
700
701void game::draw_map(view *v, int interpolate)
702{
703  backtile *bt;
704  int x1, y1, x2, y2, x, y, xo, yo, nxoff, nyoff;
705  short cx1, cy1, cx2, cy2;
706  screen->get_clip(cx1, cy1, cx2, cy2);
707
708  if(!current_level || state == MENU_STATE)
709  {
710    if(title_screen >= 0)
711    {
712      if(state == SCENE_STATE)
713        screen->set_clip(v->cx1, v->cy1, v->cx2, v->cy2);
714      image *tit = cash.img(title_screen);
715      tit->put_image(screen, screen->width()/2 - tit->width()/2,
716                    screen->height()/2 - tit->height()/2);
717      if(state == SCENE_STATE)
718        screen->set_clip(cx1, cy1, cx2, cy2);
719      wm->flush_screen();
720    }
721    return;
722  }
723
724  refresh = 0;
725
726
727  // save the dirty rect routines some work by markinging evrything in the
728  // view area dirty alreadt
729
730  if(small_render)
731    screen->add_dirty(v->cx1, v->cy1, (v->cx2 - v->cx1 + 1)*2 + v->cx1, v->cy1+(v->cy2 - v->cy1 + 1)*2);
732  else
733    screen->add_dirty(v->cx1, v->cy1, v->cx2, v->cy2);
734
735  if(v->draw_solid != -1)      // fill the screen and exit..
736  {
737    int c = v->draw_solid;
738    for(int y = v->cy1; y <= v->cy2; y++)
739      memset(screen->scan_line(y)+v->cx1, c, v->cx2 - v->cx1 + 1);
740    v->draw_solid = -1;
741    return;
742  }
743
744  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
745  image *old_screen = NULL;
746  if(small_render && (dev & DRAW_LIGHTS))  // cannot do this if we skip lighting
747  {
748    old_cx1 = v->cx1;
749    old_cy1 = v->cy1;
750    old_cx2 = v->cx2;
751    old_cy2 = v->cy2;
752
753    v->cx1 = 0;
754    v->cy1 = 0;
755    v->cx2 = small_render->width()-1;
756    v->cy2 = small_render->height()-1;
757
758    old_screen = screen;
759    screen = small_render;
760  } else
761    screen->dirt_off();
762
763
764
765//  int32_t max_xoff=(current_level->foreground_width()-1)*ftile_width()-(v->cx2 - v->cx1 + 1);
766//  int32_t max_yoff=(current_level->foreground_height()-1)*ftile_height()-(v->cy2 - v->cy1 + 1);
767
768  int32_t xoff, yoff;
769  if(interpolate)
770  {
771    xoff = v->interpolated_xoff();
772    yoff = v->interpolated_yoff();
773  } else
774  {
775    xoff = v->xoff();
776    yoff = v->yoff();
777  }
778
779//  if(xoff > max_xoff) xoff = max_xoff;
780//  if(yoff > max_yoff) yoff = max_yoff;
781
782  current_vxadd = xoff - v->cx1;
783  current_vyadd = yoff - v->cy1;
784
785  screen->set_clip(v->cx1, v->cy1, v->cx2, v->cy2);
786
787  nxoff = xoff * bg_xmul / bg_xdiv;
788  nyoff = yoff * bg_ymul / bg_ydiv;
789
790//  int32_t max_bg_xoff=(current_level->background_width())*btile_width()-(v->cx2 - v->cx1 + 1);
791//  int32_t max_bg_yoff=(current_level->background_height())*btile_height()-(v->cy2 - v->cy1 + 1);
792//  if(nxoff > max_bg_xoff) nxoff = max_xoff;
793//  if(nyoff > max_bg_yoff) nyoff = max_yoff;
794
795
796  x1 = nxoff / btile_width(); y1 = nyoff / btile_height();
797  x2 = x1+(v->cx2 - v->cx1 + btile_width())/btile_width();
798  y2 = y1+(v->cy2 - v->cy1 + btile_height())/btile_height();
799
800
801  xo = v->cx1 - nxoff % btile_width();
802  yo = v->cy1 - nyoff % btile_height();
803
804  int xinc, yinc, draw_x, draw_y;
805
806
807  if(!(dev & MAP_MODE) && (dev & DRAW_BG_LAYER))
808  {
809    xinc = btile_width();
810    yinc = btile_height();
811
812    int bh = current_level->background_height(), bw = current_level->background_width();
813    uint16_t *bl;
814    for(draw_y = yo, y = y1; y <= y2; y++, draw_y += yinc)
815    {
816      if(y >= bh)
817        bl = NULL;
818      else
819        bl = current_level->get_bgline(y)+x1;
820
821      for(x = x1, draw_x = xo; x <= x2; x++, draw_x += xinc)
822      {
823    if(x < bw && y < bh)
824    {
825          bt = get_bg(*bl);
826      bl++;
827    }
828    else bt = get_bg(0);
829
830        bt->im->put_image(screen, draw_x, draw_y);
831//        if(!(dev & EDIT_MODE) && bt->next)
832//      current_level->put_bg(x, y, bt->next);
833      }
834    }
835  }
836
837//  if(!(dev & EDIT_MODE))
838//    server_check();
839
840  uint8_t rescan = 0;
841
842    int fw, fh;
843
844    if(dev & MAP_MODE)
845    {
846      fw = AUTOTILE_WIDTH;
847      fh = AUTOTILE_HEIGHT;
848      if(dev & EDIT_MODE)
849      {
850    x1 = map_xoff;
851    y1 = map_yoff;
852      } else
853      {
854    if(v->focus)
855    {
856      x1 = v->focus->x / ftile_width()-(v->cx2 - v->cx1)/fw / 2;
857      y1 = v->focus->y / ftile_height()-(v->cy2 - v->cy1)/fh / 2;
858    } else x1 = y1 = 0;
859      }
860      if(x1 > 0)
861        xo = v->cx1-((v->focus->x * fw / ftile_width()) %fw);
862      else xo = v->cx1;
863      if(y1 > 0)
864        yo = v->cy1-((v->focus->y * fh / ftile_height()) %fh);
865      else yo = v->cy1;
866    } else
867    {
868      fw = ftile_width();
869      fh = ftile_height();
870      x1=(xoff)/fw; y1=(yoff)/fh;
871      xo = v->cx1 - xoff % fw;
872      yo = v->cy1 - yoff % fh;
873
874    }
875    if(x1 < 0) x1 = 0;
876    if(y1 < 0) y1 = 0;
877
878    x2 = x1+(v->cx2 - v->cx1 + fw)/fw;
879    y2 = y1+(v->cy2 - v->cy1 + fh)/fh;
880    if(x2 >= current_level->foreground_width())
881      x2 = current_level->foreground_width()-1;
882    if(y2 >= current_level->foreground_height())
883      y2 = current_level->foreground_height()-1;
884
885
886    xinc = fw;
887    yinc = fh;
888
889  if(dev & DRAW_FG_LAYER)
890  {
891    short ncx1, ncy1, ncx2, ncy2;
892    screen->get_clip(ncx1, ncy1, ncx2, ncy2);
893
894    int scr_w = screen->width();
895    if(dev & MAP_MODE)
896    {
897      if(dev & EDIT_MODE)
898        screen->clear(wm->bright_color());
899      else
900        screen->clear(wm->black());
901      for(y = y1, draw_y = yo; y <= y2; y++, draw_y += yinc)
902      {
903    if(!(draw_y < ncy1 ||draw_y + yinc >= ncy2))
904    {
905      uint16_t *cl = current_level->get_fgline(y)+x1;
906      uint8_t *sl1 = screen->scan_line(draw_y)+xo;
907      for(x = x1, draw_x = xo; x <= x2; x++, cl++, sl1 += xinc, draw_x += xinc)
908      {
909        if(!(draw_x < ncx1 || draw_x + xinc >= ncx2))
910        {
911          int fort_num;
912//          if(*cl & 0x8000 || (dev & EDIT_MODE))
913            fort_num = fgvalue(*cl);
914//          else fort_num = 0;
915
916          uint8_t *sl2 = get_fg(fort_num)->micro_image->scan_line(0);
917          uint8_t *sl3 = sl1;
918          memcpy(sl3, sl2, AUTOTILE_WIDTH); sl2 += AUTOTILE_WIDTH; sl3 += scr_w;
919          memcpy(sl3, sl2, AUTOTILE_WIDTH); sl2 += AUTOTILE_WIDTH; sl3 += scr_w;
920          memcpy(sl3, sl2, AUTOTILE_WIDTH);
921        }
922      }
923    }
924      }
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                            int wx = WINDOW_FRAME_LEFT, wy = WINDOW_FRAME_TOP;
1782
1783                            joy_win = wm->new_window(80, 50, -1, -1,
1784                                    new button(wx + 70, wy + 9, JOY_OK, "OK",
1785                                    new info_field(wx, wy + 30, DEV_NULL,
1786                                    " Center joystick and\n"
1787                                    "press the fire button", NULL)),
1788                                    "Joystick");
1789                            set_state(JOY_CALB_STATE);
1790                        }
1791                    }
1792                    case TOP_MENU:
1793                    {
1794                        menu_select(ev);
1795                    } break;
1796                    case DEV_QUIT:
1797                    {
1798                        finished = 1;
1799                    } break;
1800                }
1801            }
1802            else if(ev.type == EV_CLOSE_WINDOW && ev.window == top_menu)
1803            {
1804                wm->close_window(top_menu);
1805                top_menu = NULL;
1806            }
1807
1808            switch(state)
1809            {
1810                case JOY_CALB_STATE:
1811                {
1812                    joy_calb(ev);
1813                } break;
1814                case INTRO_START_STATE:
1815                {
1816                    do_intro();
1817                    if(dev & EDIT_MODE)
1818                        set_state(RUN_STATE);
1819                    else
1820                        set_state(MENU_STATE);
1821                } break;
1822                case PAUSE_STATE:
1823                {
1824                    if(ev.type == EV_KEY && (ev.key == JK_SPACE || ev.key == JK_ENTER))
1825                    {
1826                        set_state(RUN_STATE);
1827                    }
1828                } break;
1829                case RUN_STATE:
1830                {
1831                    if(ev.window == NULL)
1832                    {
1833                        switch (ev.type)
1834                        {
1835                            case EV_KEY:
1836                            {
1837                                switch (ev.key)
1838                                {
1839                                    case 'm':
1840                                    {
1841                                        if(dev & MAP_MODE)
1842                                            dev -= MAP_MODE;
1843                                        else if((player_list && player_list->next) || dev & EDIT_MODE)
1844                                            dev |= MAP_MODE;
1845
1846                                        if(!(dev & MAP_MODE))
1847                                        {
1848                                            if(dev_cont->tbw)
1849                                                dev_cont->toggle_toolbar();
1850                                            edit_mode = ID_DMODE_DRAW;
1851                                        }
1852                                        need_refresh();
1853                                    } break;
1854                                    case 'v':
1855                                    {
1856                                        wm->push_event(new event(DO_VOLUME, NULL));
1857                                    } break;
1858                                    case 'p':
1859                                    {
1860                                        if(!(dev & EDIT_MODE) && (!main_net_cfg ||
1861                                            (main_net_cfg->state != net_configuration::SERVER &&
1862                                            main_net_cfg->state != net_configuration::CLIENT)))
1863                                        {
1864                                            set_state(PAUSE_STATE);
1865                                        }
1866                                    } break;
1867                                    case 'S':
1868                                    {
1869                                        if(start_edit)
1870                                        {
1871                                            wm->push_event(new event(ID_LEVEL_SAVE, NULL));
1872                                        }
1873                                    } break;
1874                                    case JK_TAB:
1875                                    {
1876                                        if(start_edit)
1877                                            toggle_edit_mode();
1878                                        need_refresh();
1879                                    } break;
1880                                    case 'c':
1881                                    {
1882                                        if(chatting_enabled && (!(dev & EDIT_MODE) && chat))
1883                                            chat->toggle();
1884                                    } break;
1885                                    case '9':
1886                                    {
1887                                        dev = dev ^ PERFORMANCE_TEST_MODE;
1888                                        need_refresh();
1889                                    } break;
1890/*                                    case '=':
1891                                    case '+':
1892                                    {
1893                                        if(!dev_cont->need_plus_minus())
1894                                        {
1895                                            if(wm->key_pressed(JK_CTRL_L))
1896                                                grow_views(20);
1897                                            else
1898                                                grow_views(5);
1899                                            draw(state == SCENE_STATE);
1900                                        }
1901                                    } break;
1902                                    case JK_F10:
1903                                    {
1904                                        make_screen_size(311, 160);
1905                                    } break;
1906                                    case '_':
1907                                    case '-' :
1908                                    {
1909                                        if(!dev_cont->need_plus_minus())
1910                                        {
1911                                            if(wm->key_pressed(JK_CTRL_L))
1912                                                grow_views(-20);
1913                                            else
1914                                                grow_views(-5);
1915                                            draw(state == SCENE_STATE);
1916                                        }
1917                                    } break;
1918*/
1919                                }
1920                            } break;
1921                            case EV_RESIZE:
1922                            {
1923                                view *v;
1924                                for(v = first_view; v; v = v->next)  // see if any views need to change size
1925                                {
1926                                    if(v->local_player())
1927                                    {
1928                                        int w = (xres - 10)/(small_render ? 2 : 1);
1929                                        int h = (yres - 10)/(small_render ? 2 : 1);
1930
1931                                        v->suggest.send_view = 1;
1932                                        v->suggest.cx1 = 5;
1933                                        v->suggest.cx2 = 5 + w;
1934                                        v->suggest.cy1 = 5;
1935                                        v->suggest.cy2 = 5 + h;
1936                                        v->suggest.pan_x = v->pan_x;
1937                                        v->suggest.pan_y = v->pan_y;
1938                                        v->suggest.shift_down = v->shift_down;
1939                                        v->suggest.shift_right = v->shift_right;
1940                                    }
1941                                }
1942                                draw();
1943                            } break;
1944                            case EV_REDRAW:
1945                            {
1946                                screen->add_dirty(ev.redraw.x1, ev.redraw.y1,
1947                                    ev.redraw.x2, ev.redraw.y2);
1948                            } break;
1949                            case EV_MESSAGE:
1950                            {
1951                                switch (ev.message.id)
1952                                {
1953                                    case RAISE_SFX:
1954                                    case LOWER_SFX:
1955                                    case RAISE_MUSIC:
1956                                    case LOWER_MUSIC:
1957                                    {
1958                                        if(ev.message.id == RAISE_SFX && sfx_volume != 127)
1959                                            sfx_volume = min(127, sfx_volume + 16);
1960                                        if(ev.message.id == LOWER_SFX && sfx_volume != 0)
1961                                            sfx_volume = max(sfx_volume - 16, 0);
1962                                        if(ev.message.id == RAISE_MUSIC && music_volume != 126)
1963                                        {
1964                                            music_volume = min(music_volume + 16, 127);
1965                                            if(current_song && (sound_avail & MUSIC_INITIALIZED))
1966                                                current_song->set_volume(music_volume);
1967                                        }
1968
1969                                        if(ev.message.id == LOWER_MUSIC && music_volume != 0)
1970                                        {
1971                                            music_volume = max(music_volume - 16, 0);
1972                                            if(current_song && (sound_avail & MUSIC_INITIALIZED))
1973                                                current_song->set_volume(music_volume);
1974                                        }
1975
1976                                        ((button *)ev.message.data)->push();
1977/*                                        volume_window->inm->redraw();
1978                                        draw_value(volume_window->screen, WINDOW_FRAME_LEFT + 2, WINDOW_FRAME_TOP + 43,
1979                                                (volume_window->x2()-volume_window->x1()-1), 8, sfx_volume, 127);
1980                                        draw_value(volume_window->screen, WINDOW_FRAME_LEFT + 2, WINDOW_FRAME_TOP + 94,
1981                                                (volume_window->x2()-volume_window->x1()-1), 8, music_volume, 127);
1982*/
1983                                        break;
1984                                    }
1985                                }
1986                            }
1987                        }
1988                    }
1989                } break;
1990            }
1991        }
1992    }
1993}
1994
1995
1996void net_send(int force = 0)
1997{
1998  if((!(dev & EDIT_MODE)) || force)
1999  {
2000    if(demo_man.state == demo_manager::PLAYING)
2001    {
2002      base->input_state = INPUT_PROCESSING;
2003    } else
2004    {
2005
2006
2007
2008      if(!player_list->focus)
2009      {
2010    dprintf("Players have not been created\ncall create_players");
2011    exit(0);
2012      }
2013
2014
2015      view *p = player_list;
2016      for(; p; p = p->next)
2017        if(p->local_player())
2018      p->get_input();
2019
2020
2021      base->packet.write_uint8(SCMD_SYNC);
2022      base->packet.write_uint16(make_sync());
2023
2024      if(base->join_list)
2025      base->packet.write_uint8(SCMD_RELOAD);
2026
2027      //      printf("save tick %d, pk size=%d, rand_on=%d, sync=%d\n", current_level->tick_counter(),
2028      //         base->packet.packet_size(), rand_on, make_sync());
2029      send_local_request();
2030    }
2031  }
2032}
2033
2034void net_receive()
2035{
2036  if(!(dev & EDIT_MODE) && current_level)
2037  {
2038    uint8_t buf[PACKET_MAX_SIZE + 1];
2039    int size;
2040
2041    if(demo_man.state == demo_manager::PLAYING)
2042    {
2043      if(!demo_man.get_packet(buf, size))
2044        size = 0;
2045      base->packet.packet_reset();
2046      base->mem_lock = 0;
2047    } else
2048    {
2049      size = get_inputs_from_server(buf);
2050      if(demo_man.state == demo_manager::RECORDING)
2051    demo_man.save_packet(buf, size);
2052    }
2053
2054    process_packet_commands(buf, size);
2055  }
2056}
2057
2058void game::step()
2059{
2060  clear_tmp();
2061  if(current_level)
2062  {
2063    current_level->unactivate_all();
2064    total_active = 0;
2065    for(view *f = first_view; f; f = f->next)
2066    {
2067      if(f->focus)
2068      {
2069    f->update_scroll();
2070    int w, h;
2071
2072    w=(f->cx2 - f->cx1 + 1);
2073    h=(f->cy2 - f->cy1 + 1);
2074        total_active += current_level->add_actives(f->xoff()-w / 4, f->yoff()-h / 4,
2075                         f->xoff()+w + w / 4, f->yoff()+h + h / 4);
2076      }
2077    }
2078  }
2079
2080  if(state == RUN_STATE)
2081  {
2082    if((dev & EDIT_MODE) || (main_net_cfg && (main_net_cfg->state == net_configuration::CLIENT ||
2083                         main_net_cfg->state == net_configuration::SERVER)))
2084      idle_ticks = 0;
2085
2086    if(demo_man.current_state()==demo_manager::NORMAL && idle_ticks > 420 && demo_start)
2087    {
2088      idle_ticks = 0;
2089      set_state(MENU_STATE);
2090    }
2091    else if(!(dev & EDIT_MODE))               // if edit mode, then don't step anything
2092    {
2093      if(key_down(JK_ESC))
2094      {
2095    set_state(MENU_STATE);
2096    set_key_down(JK_ESC, 0);
2097      }
2098      ambient_ramp = 0;
2099      view *v;
2100      for(v = first_view; v; v = v->next)
2101        v->update_scroll();
2102
2103      cash.prof_poll_start();
2104      current_level->tick();
2105      sbar.step();
2106    } else
2107      dev_scroll();
2108  } else if(state == JOY_CALB_STATE)
2109  {
2110    event ev;
2111    joy_calb(ev);
2112  } else if(state == MENU_STATE)
2113    main_menu();
2114
2115  if(key_down('x') && (key_down(JK_ALT_L) || key_down(JK_ALT_R)) && confirm_quit()) finished = 1;
2116}
2117
2118extern void *current_demo;
2119
2120game::~game()
2121{
2122  current_demo = NULL;
2123  if(first_view == player_list) first_view = NULL;
2124  while(player_list)
2125  {
2126    view *p = player_list;
2127    game_object *o = p->focus;
2128    player_list = player_list->next;
2129    delete p;
2130    o->set_controller(NULL);
2131    if(current_level && o)
2132      current_level->delete_object(o);
2133    else delete o;
2134  }
2135
2136  if(current_level) { delete current_level; current_level = NULL; }
2137
2138  if(first_view != player_list)
2139  {
2140    while(player_list)
2141    {
2142      view *p = player_list;
2143      player_list = player_list->next;
2144      delete p;
2145    }
2146  }
2147
2148  while(first_view)
2149  {
2150    view *p = first_view;
2151    first_view = first_view->next;
2152    delete p;
2153  }
2154
2155  player_list = NULL;
2156
2157  if(old_view)
2158  {
2159    first_view = old_view;
2160    while(first_view)
2161    {
2162      view *p = first_view;
2163      first_view = first_view->next;
2164      delete p;
2165    }
2166  }
2167  old_view = NULL;
2168
2169  int i = 0;
2170  for(; i < total_objects; i++)
2171  {
2172    jfree(object_names[i]);
2173    delete figures[i];
2174  }
2175  free_pframes();
2176  if(fps_mark_start) delete fps_mark_start; fps_mark_start = NULL;
2177  delete pal;
2178  jfree(object_names);
2179  jfree(figures);
2180
2181  jfree(backtiles);
2182  jfree(foretiles);
2183  if(total_weapons)
2184    jfree(weapon_types);
2185
2186  config_cleanup();
2187  delete color_table;
2188  delete wm;
2189  delete game_font;
2190  delete big_font;
2191  delete console_font;
2192  if(total_help_screens)
2193    jfree(help_screens);
2194
2195  close_graphics();
2196  image_uninit();
2197}
2198
2199
2200
2201void game::draw(int scene_mode)
2202{
2203    screen->add_dirty(0, 0, xres, yres);
2204//    image *bt = cash.img(border_tile);
2205//    int tw = bt->width(), th = bt->height();
2206  screen->clear();
2207//  for(y = 0; y < yt; y++, dy += th)
2208//    for(x = 0, dx = 0; x < xt; x++, dx += tw)
2209//      bt->put_image(screen, dx, dy);
2210
2211    if(scene_mode)
2212    {
2213        char const *helpstr = "ARROW KEYS CHANGE TEXT SPEED";
2214        wm->font()->put_string(screen, screen->width()/2-(wm->font()->width()*strlen(helpstr))/2 + 1,
2215            screen->height()-wm->font()->height()-5 + 1, helpstr, wm->dark_color());
2216        wm->font()->put_string(screen, screen->width()/2-(wm->font()->width()*strlen(helpstr))/2,
2217            screen->height()-wm->font()->height()-5, helpstr, wm->bright_color());
2218    }
2219/*    else
2220    {
2221        char *helpstr="PRESS h FOR HELP";
2222        wm->font()->put_string(screen, screen->width()-wm->font()->width()*strlen(helpstr)-5,
2223            screen->height()-wm->font()->height()-5, helpstr);
2224    }*/
2225/*    int dc = cash.img(window_colors)->pixel(0, 2);
2226    int mc = cash.img(window_colors)->pixel(1, 2);
2227    int bc = cash.img(window_colors)->pixel(2, 2);
2228    screen->line(0, 0, screen->width()-1, 0, dc);
2229    screen->line(0, 0, 0, screen->height()-1, dc);
2230    screen->line(0, screen->height()-1, screen->width()-1, screen->height()-1, bc);
2231    screen->line(screen->width()-1, 0, screen->width()-1, screen->height()-1, bc); */
2232
2233    for(view *f = first_view; f; f = f->next)
2234        draw_map(f, 0);
2235
2236    sbar.redraw(screen);
2237}
2238
2239int external_print = 0;
2240
2241void start_sound(int argc, char **argv)
2242{
2243  sfx_volume = music_volume = 127;
2244
2245  for(int i = 1; i < argc; i++)
2246    if(!strcmp(argv[i], "-sfx_volume"))
2247    {
2248      i++;
2249      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2250        sfx_volume = atoi(argv[i]);
2251      else printf("Bad sound effects volume level, use 0..127\n");
2252    }
2253    else if(!strcmp(argv[i], "-music_volume"))
2254    {
2255      i++;
2256      if(atoi(argv[i])>=0 && atoi(argv[i])<127)
2257        music_volume = atoi(argv[i]);
2258      else printf("Bad music volume level, use 0..127\n");
2259    }
2260
2261  sound_avail = sound_init(argc, argv);
2262}
2263
2264void game_printer(char *st)
2265{
2266  if(dev_console && !external_print)
2267  {
2268    dev_console->put_string(st);
2269  }
2270  else fprintf(stderr, "%s", st);
2271}
2272
2273
2274void game_getter(char *st, int max)
2275{
2276  if(!max) return;
2277  max--;
2278  *st = 0;
2279  if(dev_console && !external_print)
2280  {
2281    dev_console->show();
2282    int t = 0;
2283    event ev;
2284    do
2285    {
2286      get_event(ev);
2287      if(ev.type == EV_KEY)
2288      {
2289    if(ev.key == JK_BACKSPACE)
2290    {
2291      if(t)
2292      {
2293        dev_console->print_f("%c", ev.key);
2294        t--;
2295        st--;
2296        *st = 0;
2297        max++;
2298      }
2299    } else if(ev.key>=' ' && ev.key<='~')
2300    {
2301      dev_console->print_f("%c", ev.key);
2302      *st = ev.key;
2303      t++;
2304      max--;
2305      st++;
2306      *st = 0;
2307    }
2308      }
2309      wm->flush_screen();
2310    } while(ev.type != EV_KEY || ev.key != JK_ENTER);
2311    dprintf("\n");
2312  }
2313  else
2314  {
2315    if(fgets(st, max, stdin))
2316    {
2317      if(*st)
2318        st[strlen(st)-1]=0;
2319    }
2320  }
2321}
2322
2323
2324void show_startup()
2325{
2326    dprintf("Abuse version %s\n", PACKAGE_VERSION);
2327}
2328
2329char *get_line(int open_braces)
2330{
2331  char *line=(char *)jmalloc(1000, "lstring");
2332  fgets(line, 1000, stdin);
2333
2334  char prev=' ';
2335  for(char *s = line; *s && (prev!=' ' || *s!=';'); s++)
2336  {
2337    prev=*s;
2338    if(*s=='(') open_braces++;
2339    else if(*s==')') open_braces--;
2340  }
2341  if(open_braces < 0)
2342    fprintf(stderr, "\nToo many)'s\n");
2343  else if(open_braces > 0)
2344  {
2345    char *s2 = get_line(open_braces);
2346    line=(char *)jrealloc(line, strlen(line)+strlen(s2)+1, "lstring");
2347    strcat(line, s2);
2348    jfree(s2);
2349  }
2350  return line;
2351}
2352
2353void check_for_upgrade(int argc, char **argv)
2354{
2355  for(int i = 1; i < argc; i++)
2356    if(!strcmp(argv[i], "-upgrade"))
2357    {
2358      lisp_init(0xf000, 0x30000);
2359      char const *prog="(load \"lisp/upgrade.lsp\")";
2360      char const *cs = prog;
2361      if(!eval(compile(cs)))
2362    printf("file \"lisp/upgrade.lsp\" does not exist, cannot upgrade\n");
2363
2364      exit(0);
2365    }
2366}
2367
2368void check_for_lisp(int argc, char **argv)
2369{
2370    for(int i = 1; i < argc; i++)
2371    {
2372        if(!strcmp(argv[i], "-lisp"))
2373        {
2374            lisp_init(0xf000, 0x30000);
2375            char const *eof_char = "Ctrl-D";
2376            fprintf(stderr,
2377                    " CLIVE (C) 1995 Jonathan Clark, all rights reserved\n"
2378                    "   (C LISP interpreter and various extentions)\n"
2379                    "Type (%s) to exit\n", eof_char);
2380
2381            while(!feof(stdin))
2382            {
2383                fprintf(stderr, "Lisp> ");
2384                char *l = get_line(0);
2385                char const *s = l;
2386                while(*s)
2387                {
2388                    void *prog = compile(s);
2389                    l_user_stack.push(prog);
2390                    while(*s==' ' || *s=='\t' || *s=='\r' || *s=='\n') s++;
2391                    lprint(eval(prog));
2392                    l_user_stack.pop(1);
2393                }
2394                jfree(l);
2395            }
2396            fprintf(stderr, "End of input : bye\n");
2397            exit(0);
2398        }
2399    }
2400}
2401
2402
2403void music_check()
2404{
2405  if(sound_avail & MUSIC_INITIALIZED)
2406  {
2407    if(current_song && !current_song->playing())
2408    {
2409      current_song->play();
2410      dprintf("song finished\n");
2411    }
2412    if(!current_song)
2413    {
2414
2415      current_song = new song("music/intro.hmi");
2416      current_song->play(music_volume);
2417
2418/*      if(DEFINEDP(symbol_function(l_next_song)))  // if user function installed, call it to load up next song
2419      {
2420    int sp = current_space;
2421    current_space = PERM_SPACE;
2422    eval_function((lisp_symbol *)l_next_song, NULL);
2423    current_space = sp;
2424      } */
2425    }
2426  }
2427}
2428
2429void setup(int argc, char **argv);
2430
2431void share_end();
2432void show_end();
2433
2434void show_sell(int abortable);
2435
2436extern pmenu *dev_menu;
2437
2438
2439extern int jmalloc_max_size;
2440extern int jmalloc_min_low_size;
2441
2442void game_net_init(int argc, char **argv)
2443{
2444  int nonet=!net_init(argc, argv);
2445  if(nonet)
2446    dprintf("No network driver, or network driver returned failure\n");
2447  else
2448  {
2449    set_file_opener(open_nfs_file);
2450    if(main_net_cfg && main_net_cfg->state == net_configuration::CLIENT)
2451    {
2452      if(set_file_server(net_server))
2453      start_running = 1;
2454      else
2455      {
2456                dprintf("Unable to attach to server, quiting\n");
2457                exit(0);
2458      }
2459    } else
2460    {
2461      int i;
2462      for(i = 1; i < argc - 1; i++)
2463      if(!strcmp(argv[i], "-fs"))
2464      if(!set_file_server(argv[i + 1]))
2465      dprintf("could not set defualt file server to %s\n", argv[i + 1]);
2466    }
2467  }
2468
2469}
2470
2471#if(defined(__APPLE__) && !defined(__MACH__))
2472extern int PixMult;
2473#if 1
2474char cmdline[256];
2475#elif 1
2476char cmdline[] = "";
2477#elif 1
2478char cmdline[] = "abuse -server -a deathmat";
2479#else
2480char cmdline[] = "abuse -net 193.246.40.9";
2481#endif
2482char delims[] = " ";
2483char *tmp_argv[255];
2484
2485void GetArgs(int &argc, char **(&argv))
2486{
2487    char *s;
2488
2489    printf("Usage:\n"
2490                    "  abuse [-options]\n\n"
2491                    "  Options:\n"
2492                    "    -server -a deathmat        become a server for deathmatch game\n"
2493                    "    -net <dotted ip address>   connect to a server\n\n"
2494                    "Options for mac:\n"
2495                    "  Hold down <control> for single pixel mode\n"
2496                    "  Hold down <option> for edit mode\n"
2497                    "  Hold down <left shift> for double size mode\n\n"
2498                    "If started with no command line options, networking will attempt\n"
2499                    "  to search the local network for servers\n\n"
2500);
2501    printf("Enter command line:\n");
2502    gets(cmdline);
2503
2504    argc = 0;
2505    argv = tmp_argv;
2506    s = strtok(cmdline, delims);
2507    while(s)
2508    {
2509        argv[argc] = s;
2510        argc++;
2511        s = strtok(0, delims);
2512    }
2513    argv[argc] = 0;
2514}
2515
2516#endif
2517
2518int main(int argc, char **argv)
2519{
2520#if(defined(__APPLE__) && !defined(__MACH__))
2521    GetArgs(argc, argv);
2522#endif
2523
2524    start_argc = argc;
2525    start_argv = argv;
2526
2527    for(int i = 0; i < argc; i++)
2528    {
2529        if(!strcmp(argv[i], "-cprint"))
2530        {
2531            external_print = 1;
2532        }
2533
2534        if(!strcmp(argv[i], "-min_low"))
2535        {
2536            i++;
2537            jmalloc_min_low_size = atoi(argv[i]);
2538        }
2539    }
2540
2541//  jmalloc_max_size = 0x150000;
2542    jmalloc_init(0x150000);
2543//  jmalloc_init(100000);
2544
2545#if(defined(__APPLE__) && !defined(__MACH__))
2546    unsigned char km[16];
2547
2548    fprintf(stderr, "Mac Options: ");
2549    xres = 320; yres = 200;
2550    GetKeys((uint32_t*)&km);
2551    if((km[ 0x3a >>3] >> (0x3a & 7)) &1 != 0)
2552    {
2553        dev|=EDIT_MODE;
2554        start_edit = 1;
2555        start_running = 1;
2556        disable_autolight = 1;
2557        fprintf(stderr, "Edit Mode...");
2558    }
2559    if((km[ 0x3b >>3] >> (0x3b & 7)) &1 != 0)
2560    {
2561        PixMult = 1;
2562        fprintf(stderr, "Single Pixel...");
2563    }
2564    else
2565    {
2566        PixMult = 2;
2567        fprintf(stderr, "Double Pixel...");
2568    }
2569    if((km[ 0x38 >>3] >> (0x38 & 7)) &1 != 0)
2570    {
2571        xres *= 2;  yres *= 2;
2572        fprintf(stderr, "Double Size...");
2573    }
2574    fprintf(stderr, "\n");
2575
2576    if(tcpip.installed())
2577        fprintf(stderr, "Using %s\n", tcpip.name());
2578#endif
2579
2580    set_dprinter(game_printer);
2581    set_dgetter(game_getter);
2582    set_no_space_handler(handle_no_space);
2583
2584    setup(argc, argv);
2585
2586    show_startup();
2587
2588    start_sound(argc, argv);
2589
2590    stat_man = new text_status_manager();
2591    if(!get_option("-no_timer"))
2592    {
2593        timer_init();
2594    }
2595
2596    // look to see if we are supposed to fetch the data elsewhere
2597    if(getenv("ABUSE_PATH"))
2598    {
2599        set_filename_prefix(getenv("ABUSE_PATH"));
2600    }
2601
2602    // look to see if we are supposed to save the data elsewhere
2603    if(getenv("ABUSE_SAVE_PATH"))
2604    {
2605        set_save_filename_prefix(getenv("ABUSE_SAVE_PATH"));
2606    }
2607
2608    jrand_init();
2609    jrand();        // so compiler doesn't complain
2610
2611    set_spec_main_file("abuse.spe");
2612
2613    check_for_lisp(argc, argv);
2614    check_for_upgrade(argc, argv);
2615
2616    do
2617    {
2618        if(main_net_cfg)
2619        {
2620            if(!main_net_cfg->notify_reset())
2621            {
2622                if(!get_option("-no_timer"))
2623                    timer_uninit();
2624                sound_uninit();
2625                exit(0);
2626            }
2627        }
2628
2629        game_net_init(argc, argv);
2630        lisp_init(0x16000, 0x94000);
2631//        lisp_init(0x100000, 0x10000);
2632
2633        dev_init(argc, argv);
2634
2635        game *g = new game(argc, argv);
2636
2637        dev_cont = new dev_controll();
2638        dev_cont->load_stuff();
2639
2640        g->get_input();        // prime the net
2641
2642        int xx;
2643        for(xx = 1; xx < argc; xx++)
2644        {
2645            if(!strcmp(argv[xx], "-server"))
2646            {
2647                xx++;
2648                if(!become_server(argv[xx]))
2649                {
2650                    dprintf("unable to become a server\n");
2651                    exit(0);
2652                }
2653                xx = argc + 1;
2654            }
2655        }
2656
2657        if(main_net_cfg)
2658        {
2659            wait_min_players();
2660        }
2661
2662        net_send(1);
2663        if(net_start())
2664        {
2665            g->step();                // process all the objects in the
2666            g->calc_speed();
2667            g->update_screen();        // redraw the screen with any changes
2668        }
2669
2670    while(!g->done())
2671    {
2672      music_check();
2673
2674      if(req_end)
2675      {
2676                delete current_level;
2677                current_level = NULL;
2678
2679                show_end();
2680
2681                the_game->set_state(MENU_STATE);
2682                req_end = 0;
2683      }
2684
2685      if(demo_man.current_state()==demo_manager::NORMAL)
2686      {
2687                net_receive();
2688      }
2689
2690      if(req_name[0])            // see if a request for a level load was made during the last tick
2691      {
2692        g->load_level(req_name);
2693        req_name[0]=0;
2694        g->draw(g->state == SCENE_STATE);
2695      }
2696
2697      //    if(demo_man.current_state()!=demo_manager::PLAYING)
2698      g->get_input();
2699
2700      if(demo_man.current_state()==demo_manager::NORMAL)
2701      net_send();
2702      else demo_man.do_inputs();
2703
2704      service_net_request();
2705
2706      g->step();                        // process all the objects in the
2707
2708      server_check();
2709
2710      g->calc_speed();
2711      if(!req_name[0])                // see if a request for a level load was made during the last tick
2712        g->update_screen();               // redraw the screen with any changes
2713
2714
2715    }
2716
2717    net_uninit();
2718
2719    if(net_crcs)
2720    {
2721      net_crcs->clean_up();
2722      delete net_crcs;
2723      net_crcs = NULL;
2724    }
2725
2726    delete chat;
2727
2728    milli_wait(500);
2729
2730    if(small_render) { delete small_render; small_render = NULL; }
2731
2732    if(current_song)
2733    { current_song->stop();
2734      delete current_song;
2735      current_song = NULL;
2736    }
2737
2738
2739    cash.empty();
2740
2741
2742    if(dev_console)
2743    {
2744      delete dev_console;
2745      dev_console = NULL;
2746    }
2747
2748    if(dev_menu)
2749    {
2750      delete dev_menu;
2751      dev_menu = NULL;
2752    }
2753
2754    delete g;
2755    if(old_pal) delete old_pal; old_pal = NULL;
2756    compiled_uninit();
2757    delete_all_lights();
2758    jfree(white_light_initial);
2759
2760    for(int i = 0; i < TTINTS; i++) jfree(tints[i]);
2761
2762
2763    dev_cleanup();
2764    delete dev_cont; dev_cont = NULL;
2765    delete stat_man;
2766    stat_man = new text_status_manager();
2767
2768    if(!(main_net_cfg && main_net_cfg->restart_state()))
2769    {
2770      void *end_msg = make_find_symbol("end_msg");
2771      if(DEFINEDP(symbol_value(end_msg)))
2772      printf("%s\n", lstring_value(symbol_value(end_msg)));
2773    }
2774
2775    lisp_uninit();
2776
2777    base->packet.packet_reset();
2778    mem_report("end.mem");
2779  } while(main_net_cfg && main_net_cfg->restart_state());
2780
2781    delete stat_man;
2782
2783    if(main_net_cfg)
2784    {
2785        delete main_net_cfg;
2786        main_net_cfg = NULL;
2787    }
2788    set_filename_prefix(NULL);  // dealloc this mem if there was any
2789    set_save_filename_prefix(NULL);
2790
2791    if(!get_option("-no_timer"))
2792    {
2793        timer_uninit();
2794    }
2795
2796// AK -> Commented this out to stop a crash as the file prefix has already
2797//       been released.  Need to fix this.
2798//    mem_report("end.mem");
2799
2800//    jmalloc_uninit();
2801    l_user_stack.clean_up();
2802    l_ptr_stack.clean_up();
2803
2804    sound_uninit();
2805
2806    exit(0);
2807
2808    return 0;
2809}
2810
Note: See TracBrowser for help on using the repository browser.