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

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