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

Last change on this file since 682 was 682, checked in by Sam Hocevar, 8 years ago

core: rename vec2i to ivec2 and update matrix.h from Lol Engine.

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