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

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