source: abuse/branches/lol/src/game.cpp @ 732

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

build: SDL2 compilation fixes.

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