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