source: abuse/trunk/src/dev.cpp @ 657

Last change on this file since 657 was 657, checked in by Sam Hocevar, 11 years ago

game: refactor the mouse/game coordinate conversion logic.

File size: 98.7 KB
Line 
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 <string.h>
17
18#include "common.h"
19
20#include "dev.h"
21#include "input.h"
22#include "objects.h"
23#include "id.h"
24#include "lisp.h"
25#include "light.h"
26#include "devsel.h"
27#include "dprint.h"
28#include "property.h"
29#include "pmenu.h"
30#include "filesel.h"
31#include "tools.h"
32#include "game.h"
33#include "pcxread.h"
34#include "lisp_gc.h"
35#include "demo.h"
36#include "profile.h"
37#include "sbar.h"
38#include "compiled.h"
39#include "chat.h"
40
41#define make_above_tile(x) ((x)|0x4000)
42char backw_on=0,forew_on=0,show_menu_on=0,ledit_on=0,pmenu_on=0,omenu_on=0,commandw_on=0,tbw_on=0,
43     searchw_on=0,small_render_on=0,interpolate_draw=0,disable_autolight=0,fps_on=0,profile_on=0,
44     show_names=0,fg_reversed=0,
45     raise_all;
46
47char const *symbol_str(char const *name)
48{
49  LSymbol *sym = LSymbol::FindOrCreate(name);
50  if (sym->GetValue() && item_type(sym->GetValue())==L_STRING)
51    return lstring_value(sym->GetValue());
52
53
54  // maybe english.lsp was not loaded yet, let's try to do that
55  LSpace *sp = LSpace::Current;
56  LSpace::Current = &LSpace::Perm;
57
58  char prog[50];
59  char const *cs=prog;
60  strcpy(prog,"(setq section 'game_section)\n");
61  LObject::Compile(cs)->Eval();
62  strcpy(prog,"(load \"lisp/english.lsp\")\n");
63  cs=prog;
64  if (!LObject::Compile(cs)->Eval())
65  {
66    printf("unable to open file '%s'\n",lsf);
67    exit(0);
68  }
69  LSpace::Current=sp;
70
71
72  // check again to see if the symbol is there
73  sym = LSymbol::FindOrCreate(name);
74  if (sym->GetValue() && item_type(sym->GetValue())==L_STRING)
75    return lstring_value(sym->GetValue());
76
77
78  // check to see if there is a missing symbol definition
79  sym = LSymbol::FindOrCreate("missing_sym");
80  if (sym->GetValue() && item_type(sym->GetValue())==L_STRING)
81    return lstring_value(sym->GetValue());
82
83  // last resort, return english string
84  return "Missing language symbol!";
85}
86
87
88static game_object *copy_object=NULL;
89
90pmenu *dev_menu=NULL;
91Jwindow *mess_win=NULL,*warn_win=NULL;
92
93game_object *edit_object;
94dev_controll *dev_cont=NULL;
95image *small_render=NULL;
96
97int scale_mult,scale_div,dlastx,dlasty;
98int last_created_type=-1;
99char level_file[100]="levels/level00.spe";
100
101
102class cached_image : public visual_object
103{
104  int id;
105  public :
106  cached_image(int Id) { id=Id; }
107  virtual void draw(image *screen, int x, int y, Filter *f)
108  {
109    if (f)
110      f->PutImage(screen, cache.img(id), vec2i(x, y));
111    else
112      screen->PutImage(cache.img(id), vec2i(x, y));
113  }
114  virtual int width() { return cache.img(id)->Size().x; }
115  virtual int height() { return cache.img(id)->Size().y; }
116} ;
117
118
119#define DEV_MODES 3
120cached_image *dev_mode_pict[DEV_MODES];
121
122int dev_del,dev_move, dev_char_left,dev_char_right,dev_back,dev_front,dev_ok,dev_copy,dev_brain,
123    dev_lights,dev_objects,dev_ai,dev_mode_icon[DEV_MODES],
124    dev_forward,dev_backward;
125
126char const *dev_mode_icon_names[DEV_MODES] =
127{
128    "pixel_mode", "pick_mode", /* "fill_mode",
129    "line_mode","rect_mode","bar_mode", */ "area_select"
130};
131
132int dev_mode_ids[DEV_MODES]={ ID_DMODE_DRAW,ID_DMODE_PICK, ID_DMODE_AREA};
133
134int edit_mode=ID_DMODE_DRAW;
135
136
137dev_term *dev_console=NULL;
138int ldef_width=0,ldef_height=0,ldef_r1=1,ldef_r2=100;
139
140void make_screen_size(int w, int h);
141
142class amb_cont : public scroller
143{
144  public :
145  amb_cont(int X, int Y, ifield *Next) : scroller(X,Y,ID_NULL,100,wm->font()->height()+2,0,64,Next)
146  { if (player_list) sx=player_list->ambient; }
147  virtual void scroll_event(int newx, image *screen)
148  {
149    screen->Bar(vec2i(x, y), vec2i(x + l - 1, y + h - 1), wm->dark_color());
150    char st[100];
151    sprintf(st,"%d",newx);
152    wm->font()->put_string(screen,x+30,y+1,st,wm->bright_color());
153    if (player_list)
154      player_list->ambient=newx;
155    the_game->need_refresh();
156  }
157} ;
158
159
160int confirm_quit()
161{
162    Jwindow *quitw;
163    image *ok_image, *cancel_image;
164
165    ok_image = cache.img(cache.reg("art/frame.spe", "dev_ok",
166                                 SPEC_IMAGE, 1))->copy();
167    cancel_image = cache.img(cache.reg("art/frame.spe", "cancel",
168                                     SPEC_IMAGE, 1))->copy();
169
170    quitw = wm->new_window(xres / 2 + 40, yres / 2, 80, -1,
171              new button(10, wm->font()->height() + 4, ID_QUIT_OK, ok_image,
172              new button(38, wm->font()->height() + 4, ID_CANCEL, cancel_image,
173              new info_field(2, 2, ID_NULL, symbol_str("sure?"), NULL))),
174              symbol_str("quit_title"));
175
176    wm->grab_focus(quitw);
177    int fin = 0, quit = 0;
178
179    while(!fin)
180    {
181        wm->flush_screen();
182
183        Event ev;
184        wm->get_event(ev);
185        if(ev.type == EV_MESSAGE && ev.message.id == ID_QUIT_OK)
186            fin = quit = 1;
187        else if(ev.type == EV_MESSAGE && ev.message.id == ID_CANCEL)
188            fin = 1;
189        else if(ev.type == EV_KEY
190                 && toupper(ev.key) == toupper(*symbol_str("YES")))
191            fin = quit = 1;
192        else if(ev.type == EV_KEY
193                 && toupper(ev.key) == toupper(*symbol_str("NO")))
194            fin = 1;
195        if((ev.type == EV_KEY && ev.key == JK_ESC)
196           || ev.type == EV_CLOSE_WINDOW)
197            fin = 1;
198    }
199
200    delete ok_image;
201    delete cancel_image;
202
203    the_game->reset_keymap();
204
205    wm->close_window(quitw);
206    wm->flush_screen();
207    return quit;
208}
209
210static void show_object_number (game_object *who)
211{
212  int total=0,number=0;
213  game_object *c;
214  for (c=current_level->first_object(); c; c=c->next)
215  {
216    if (c->otype==who->otype)
217      total++;
218    if (c==who) number=total;
219  }
220  char msg[100];
221  sprintf(msg,"%s : %d of %d",object_names[who->otype],number,total);
222}
223
224void dev_controll::search_backward()
225{ ;
226}
227
228
229static void single_render()
230{
231  // enlarge clip area
232  the_game->first_view->cx2=the_game->first_view->cx1+
233                            (the_game->first_view->cx2-the_game->first_view->cx1+1)*2;
234  the_game->first_view->cy2=the_game->first_view->cy1+
235                            (the_game->first_view->cy2-the_game->first_view->cy1+1)*2;
236  delete small_render;
237  small_render=NULL;
238  small_render_on=0;
239}
240
241static void double_render()
242{
243  small_render_on=1;
244  // reduce clip area
245  the_game->first_view->cx2=the_game->first_view->cx1+
246                            (the_game->first_view->cx2-the_game->first_view->cx1+1)/2;
247  the_game->first_view->cy2=the_game->first_view->cy1+
248                            (the_game->first_view->cy2-the_game->first_view->cy1+1)/2;
249
250  small_render=new image(vec2i(the_game->first_view->cx2-the_game->first_view->cx1+1, the_game->first_view->cy2-the_game->first_view->cy1+1),NULL,2);
251}
252
253
254void dev_controll::search_forward()
255{
256  if (search_window) // if no window then we can't get the object name
257  {
258    char *name=search_window->read(ID_SEARCH_TEXT);
259    int type=-1;    // see if this type existss
260    int i;
261    for (i=0; i<total_objects; i++)
262      if (!strcmp(object_names[i],name))
263        type=i;
264    if (type==-1)
265    {
266      char msg[60];
267      sprintf(msg,"Object type '%s' does not existss!\n",name);
268      the_game->show_help(msg);
269      the_game->need_refresh();
270    } else
271    {
272      game_object *first,*find=NULL;
273      if (!search_object || search_object->otype!=type)
274        first=current_level->first_object();
275      else
276        first=search_object->next;
277      for (; !find && first; first=first->next)
278        if (first->otype==type)
279      find=first;
280      if (!find)
281      {
282    for (first=current_level->first_object(); first && !find; first=first->next)
283    {
284      if (first->otype==type)
285        find=first;
286    }
287      }
288      if (find)
289      {
290        search_object=find;
291    show_object_number(search_object);
292      }
293      else
294      {
295    the_game->show_help("No object matching name exists in level\n");
296
297      }
298    }
299  }
300}
301
302
303int32_t dev_controll::snap_x(int32_t x)
304{
305  if (wm->key_pressed(JK_CTRL_L) || wm->key_pressed(JK_CTRL_R))
306    return x-(x%the_game->ftile_width());
307  else if (wm->key_pressed(JK_ALT_L) || wm->key_pressed(JK_ALT_R))
308    return x-(x%the_game->ftile_width())+the_game->ftile_width()/2;
309  else return x;
310}
311
312int32_t dev_controll::snap_y(int32_t y)
313{
314  if (wm->key_pressed(JK_CTRL_L) || wm->key_pressed(JK_CTRL_R))
315    return y-(y%the_game->ftile_height())-1;
316  else if (wm->key_pressed(JK_ALT_L) || wm->key_pressed(JK_ALT_R))
317    return y-(y%the_game->ftile_height())+the_game->ftile_height()/2-1;
318  else return y;
319}
320
321void dev_controll::make_ambient()
322{
323    if(ambw)
324        return;
325
326    ambw = wm->new_window(prop->getd("ambient x", -1),
327                          prop->getd("ambient y", -1), -1, -1,
328                          new amb_cont(0, 0, NULL), "ambient");
329}
330
331void dev_term::execute(char *st)
332{
333  if (!strcmp(st,"?"))
334  {
335    put_string("unchop x y, size x y,\n"
336           "load, esave, name\n");
337  } else
338  {
339    Event ev;
340    dv->do_command(st,ev);
341  }
342}
343
344static void load_dev_icons()
345{
346  char const *artf="art/dev.spe";
347  dev_del=cache.reg(artf,"dev_del",SPEC_IMAGE,0);
348  dev_move=cache.reg(artf,"dev_move",SPEC_IMAGE,0);
349  dev_char_left=cache.reg(artf,"dev_char_left",SPEC_IMAGE,0);
350  dev_char_right=cache.reg(artf,"dev_char_right",SPEC_IMAGE,0);
351  dev_back=cache.reg(artf,"dev_back",SPEC_IMAGE,0);
352  dev_front=cache.reg(artf,"dev_front",SPEC_IMAGE,0);
353  dev_ok=cache.reg(artf,"dev_ok",SPEC_IMAGE,0);
354  dev_copy=cache.reg(artf,"dev_copy",SPEC_IMAGE,0);
355  dev_brain=cache.reg(artf,"brain",SPEC_IMAGE,0);
356  dev_lights=cache.reg(artf,"lights",SPEC_IMAGE,0);
357  dev_objects=cache.reg(artf,"objects",SPEC_IMAGE,0);
358  dev_ai=cache.reg(artf,"ai",SPEC_IMAGE,0);
359  dev_forward=cache.reg(artf,"forward",SPEC_IMAGE,0);
360  dev_backward=cache.reg(artf,"backward",SPEC_IMAGE,0);
361
362  for (int i=0; i<DEV_MODES; i++)
363    dev_mode_icon[i]=cache.reg(artf,dev_mode_icon_names[i],SPEC_IMAGE,0);
364
365}
366
367void scale_put(image *im, image *screen, int x, int y, short new_width, short new_height)
368{
369  unsigned char *sl1,*sl2;
370  int32_t xstep=(im->Size().x<<16)/new_width,
371       ystep=(im->Size().y<<16)/new_height,iy,ix,sx,ix_start,iy_start;
372  screen->AddDirty(x, y, x + new_width, y + new_height);
373
374  int cx1, cy1, cx2, cy2;
375  screen->GetClip(cx1, cy1, cx2, cy2);
376  if (cx1>cx2 || cy1>cy2 || x>cx2-1 || y>cy2-1 || x+new_width<=cx1 || y+new_height<=cy1) return ;
377  if (x<cx1)
378  {
379    ix_start=(cx1-x)*xstep;
380    new_width-=(cx1-x);
381    x=cx1;
382  } else ix_start=0;
383  if (x+new_width>cx2)
384    new_width-=x+new_width-cx2;
385  if (y<cy1)
386  {
387    iy_start=(cy1-y)*ystep;
388    new_height-=(cy1-y);
389    y=cy1;
390  } else iy_start=0;
391  if (y+new_height>cy2)
392    new_height-=y+new_height-cy2;
393
394  screen->Lock();
395  im->Lock();
396  for (iy=iy_start; new_height>0; new_height--,y++,iy+=ystep)
397  {
398    sl1=im->scan_line(iy>>16);
399    sl2=screen->scan_line(y)+x;
400    for (ix=ix_start,sx=0; sx<new_width; sx++,ix+=xstep,sl2++)
401      *sl2=sl1[ix>>16];
402  }
403  im->Unlock();
404  screen->Unlock();
405}
406
407
408void scale_put_trans(image *im, image *screen, int x, int y, short new_width, short new_height)
409{
410  unsigned char *sl1,*sl2;
411  int32_t xstep=(im->Size().x<<16)/new_width,
412       ystep=(im->Size().y<<16)/new_height,iy,ix,sx,ix_start,iy_start;
413  screen->AddDirty(x, y, x + new_width, y + new_height);
414
415  int cx1, cy1, cx2, cy2;
416  screen->GetClip(cx1, cy1, cx2, cy2);
417  if (cx1>cx2 || cy1>cy2 || x>cx2-1 || y>cy2-1 || x+new_width<=cx1 || y+new_height<=cy1) return ;
418  if (x<cx1)
419  {
420    ix_start=(cx1-x)*xstep;
421    new_width-=(cx1-x);
422    x=cx1;
423  } else ix_start=0;
424  if (x+new_width>cx2)
425    new_width-=x+new_width-cx2;
426  if (y<cy1)
427  {
428    iy_start=(cy1-y)*ystep;
429    new_height-=(cy1-y);
430    y=cy1;
431  } else iy_start=0;
432  if (y+new_height>cy2)
433    new_height-=y+new_height-cy2;
434
435  uint8_t d;
436  screen->Lock();
437  for (iy=iy_start; new_height>0; new_height--,y++,iy+=ystep)
438  {
439    sl1=im->scan_line(iy>>16);
440    sl2=screen->scan_line(y)+x;
441    for (ix=ix_start,sx=0; sx<new_width; sx++,ix+=xstep,sl2++)
442    {
443      d=sl1[ix>>16];
444      if (d)
445        *sl2=d;
446    }
447  }
448  screen->Unlock();
449}
450
451int dev_controll::need_plus_minus()
452{
453  if (state==DEV_MOVE_LIGHT) return 1; else return 0;
454}
455
456int dev_controll::need_arrows()
457{
458  if (state==DEV_MOVE_LIGHT) return 1; else return 0;
459}
460
461int dev_controll::repeat_key_mode()
462{
463  if (state==DEV_MOVE_LIGHT) return 1; else return 0;
464}
465
466int last_link_x=0,last_link_y=0;
467
468void dev_controll::dev_draw(view *v)
469{
470  int32_t x1,y1,x2,y2;
471  if (dev&EDIT_MODE)
472  {
473    int32_t vx=v->xoff(),vy=v->yoff();
474
475    if (dev&DRAW_LINKS)
476    {
477      for (light_source *f=first_light_source; f; f=f->next)
478      {
479    if (f->x-vx>=0 && f->x-vx<=(v->cx2-v->cx1+1) && f->y-vy>=0 && f->y-vy<=(v->cy2-v->cy1+1))
480    {
481      image *im = cache.img(light_buttons[f->type]);
482      main_screen->PutImage(im, vec2i(f->x - vx + v->cx1 - im->Size().x / 2,
483                                      f->y - vy + v->cy1 - im->Size().y / 2), 1);
484      main_screen->Rectangle(vec2i(f->x1 - vx + v->cx1, f->y1 - vy + v->cy1),
485                             vec2i(f->x2 - vx + v->cx1, f->y2 - vy + v->cy1),
486                             wm->medium_color());
487    }
488      }
489    }
490
491    if (link_object)
492    {
493      vec2i pos = the_game->GameToMouse(vec2i(link_object->x, link_object->y), v);
494      main_screen->Line(pos, vec2i(dlastx, dlasty), yellow);
495    }
496
497    if (selected_light)
498    {
499      image *im = cache.img(light_buttons[0]);
500      vec2i pos = the_game->GameToMouse(vec2i(selected_light->x, selected_light->y), v);
501      main_screen->Rectangle(pos - im->Size() / 2, pos + im->Size() / 2,
502                             wm->bright_color());
503    }
504
505    game_object *o;
506    if (show_names)
507      for (o=current_level->first_object(); o; o=o->next)
508      {
509    vec2i pos = the_game->GameToMouse(vec2i(o->x, o->y), current_view);
510    char *nm=object_names[o->otype];
511    console_font->put_string(main_screen, pos.x - strlen(nm) * console_font->width() / 2, pos.y + 2, nm);
512      }
513
514    if (dev&DRAW_LINKS)
515    {
516      // draw connections between objects
517      for (o=current_level->first_object(); o; o=o->next)
518      {
519    vec2i pos1 = the_game->GameToMouse(vec2i(o->x, o->y), current_view);
520
521    int i=0;
522    for (; i<o->total_objects(); i++)
523    {
524      game_object *other=o->get_object(i);
525      vec2i pos2 = the_game->GameToMouse(vec2i(other->x, other->y), current_view);
526      main_screen->Line(pos1, pos2, wm->bright_color());
527    }
528
529    for (i=0; i<o->total_lights(); i++)
530    {
531      light_source *l=o->get_light(i);
532      vec2i pos2 = the_game->GameToMouse(vec2i(l->x, l->y), current_view);
533      main_screen->Line(pos1, pos2, light_connection_color);
534    }
535
536      }
537    }
538
539    if (selected_object)
540    {
541      selected_object->picture_space(x1,y1,x2,y2);
542      vec2i pos1 = the_game->GameToMouse(vec2i(x1, y1), v);
543      vec2i pos2 = the_game->GameToMouse(vec2i(x2, y2), v);
544      main_screen->Rectangle(pos1, pos2, wm->bright_color());
545
546      pos1 = the_game->GameToMouse(vec2i(selected_object->x, selected_object->y), current_view);
547      for (int i=0; i<selected_object->total_objects(); i++)
548      {
549        game_object *other = selected_object->get_object(i);
550        pos2 = the_game->GameToMouse(vec2i(other->x, other->y), current_view);
551        main_screen->Line(pos1, pos2, light_connection_color);
552      }
553    }
554  }
555}
556
557static light_source *find_light(int32_t x, int32_t y)
558{
559  image *i=cache.img(light_buttons[0]);
560  int l=i->Size().x/2,h=i->Size().y/2;
561  for (light_source *f=first_light_source; f; f=f->next)
562  {
563    if (x>=f->x-l && x<=f->x+l && y>=f->y-h && y<=f->y+h)
564      return f;
565  }
566  return NULL;
567}
568
569
570void dev_controll::toggle_toolbar()
571{
572  if (tbw)
573  {
574    tbw_on=0;
575    prop->setd("toolbar x",tbw->x);
576    prop->setd("toolbar y",tbw->y);
577    wm->close_window(tbw);
578    tbw=NULL;
579  } else
580  {
581    tbw_on=1;
582    int setx=0;
583    for (int i=0; i<DEV_MODES; i++)
584    {
585      if (edit_mode==dev_mode_ids[i])
586        setx=i;
587      dev_mode_pict[i]=new cached_image(dev_mode_icon[i]);
588    }
589
590    tool_picker *tp=new tool_picker(0, 0,
591                         ID_NULL,
592                         5,(visual_object **)dev_mode_pict,dev_mode_ids,DEV_MODES,
593                        pal,pal,NULL);
594    tbw=wm->new_window(prop->getd("toolbar x",-1),
595               prop->getd("toolbar y",-1),-1,-1,tp);
596    tp->set_x(setx,tbw->m_surf);
597  }
598}
599
600void dev_controll::toggle_show_menu()
601{
602    if(show_menu)
603    {
604        show_menu_on = 0;
605        prop->setd("layer x", show_menu->x);
606        prop->setd("layer y", show_menu->y);
607        wm->close_window(show_menu);
608        show_menu = NULL;
609        return;
610    }
611
612    show_menu_on = 1;
613
614    button *lnb, *lb, *cb, *bb, *bdb, *fb;
615
616    lnb = new button(0, 100, SHOW_LINKS, symbol_str("l_links"), NULL);
617    if(dev & DRAW_LINKS)
618        lnb->push();
619    lb = new button(0, 80, SHOW_LIGHT, symbol_str("l_light"), lnb);
620    if(dev & DRAW_LIGHTS)
621        lb->push();
622    cb = new button(0, 60, SHOW_CHARACTERS, symbol_str("l_char"), lb);
623    if(dev & DRAW_PEOPLE_LAYER)
624        cb->push();
625    bb = new button(0, 40, SHOW_BACKGROUND, symbol_str("l_back"), cb);
626    if(dev & DRAW_BG_LAYER)
627        bb->push();
628    bdb = new button(0, 20, SHOW_FOREGROUND_BOUND, symbol_str("l_bound"), bb);
629    if(dev & DRAW_FG_BOUND_LAYER)
630        bdb->push();
631    fb = new button(0, 0, SHOW_FOREGROUND, symbol_str("l_fore"), bdb);
632    if(dev & DRAW_FG_LAYER)
633        fb->push();
634
635    show_menu = wm->new_window(prop->getd("layer x", -1),
636                               prop->getd("layer y", -1), -1, -1,
637                               fb, symbol_str(symbol_str("SHOW?")));
638}
639
640char **listable_objs=NULL;
641int total_listable;
642
643void dev_controll::toggle_omenu()
644{
645    if(omenu)
646    {
647        omenu_on = 0;
648        prop->setd("objects x", omenu->x);
649        prop->setd("objects y", omenu->y);
650        wm->close_window(omenu);
651        omenu = NULL;
652        free(listable_objs);
653        listable_objs = NULL;
654        return;
655    }
656
657    omenu_on = 1;
658    total_listable = 0;
659
660    int i, c;
661
662    for(i = 0; i < total_objects; i++)
663        if(!figures[i]->get_cflag(CFLAG_UNLISTABLE))
664            total_listable++;
665    listable_objs = (char **)malloc(sizeof(char *) * total_listable);
666
667    for(i = 0, c = 0; i < total_objects; i++)
668        if(!figures[i]->get_cflag(CFLAG_UNLISTABLE))
669        {
670            listable_objs[c] = object_names[i];
671            c++;
672        }
673
674    omenu = wm->new_window(prop->getd("objects x", 0),
675                           prop->getd("objects y", 0), -1, -1,
676                           new pick_list(0, 0, DEV_CREATE,
677                                         yres / wm->font()->height() / 2,
678                                         listable_objs, total_listable, 0,
679                                         NULL, cache.img(window_texture)));
680}
681
682static int get_omenu_item(int x)
683{
684  for (int i=0; i<total_objects; i++)
685    if (listable_objs[x]==object_names[i])
686      return i;
687  return 0;
688}
689
690void dev_controll::toggle_pmenu()
691{
692    if(pmenu)
693    {
694        pmenu_on = 0;
695        prop->setd("pal x", pmenu->x);
696        prop->setd("pal y", pmenu->y);
697        wm->close_window(pmenu);
698        pmenu = NULL;
699        free(pwin_list);
700        return;
701    }
702
703    if(!total_pals)
704    {
705        the_game->show_help(symbol_str("no_pals"));
706        return;
707    }
708
709    pmenu_on = 1;
710
711    pwin_list = (char **)malloc(total_pals * sizeof(char *));
712    for(int i = 0; i < total_pals; i++)
713        pwin_list[i] = pal_wins[i]->name;
714
715    pmenu = wm->new_window(prop->getd("pal x",0),
716                           prop->getd("pal y",-1), -1,-1,
717                           new pick_list(0, 0, DEV_PALETTE,
718                                         yres / wm->font()->height() / 2,
719                                         pwin_list, total_pals, 0, NULL,
720                                         cache.img(window_texture)));
721}
722
723
724void dev_controll::toggle_fgw()
725{
726    if(forew)
727    {
728        forew_on = 1;
729        prop->setd("fore x", forew->x);
730        prop->setd("fore y", forew->y);
731        wm->close_window(forew);
732        forew = NULL;
733        return;
734    }
735
736    /* FIXME: shouldn't this be 1? */
737    forew_on = 0;
738    int maxh = (yres - 25) / (the_game->ftile_height() / fg_scale);
739
740    /* FIXME: previous code had 1 instead of 0, investigate */
741    tile_picker *f_tp = new tile_picker(0, 0, DEV_FG_PICKER, SPEC_FORETILE,
742                                        fg_scale, maxh, fg_w, NULL);
743    f_tp->reverse();
744
745    forew = wm->new_window(prop->getd("fore x", -30), prop->getd("fore y", 0),
746                           -1, -1, f_tp,symbol_str("l_fg"));
747}
748
749void dev_controll::toggle_music_window()
750{
751/*  if (!music_window)
752  {
753    music_window=wm->new_window(-1,30,0,0,
754             new pick_list(0,0,DEV_MUSIC_PICKLIST,10,song_list,total_songs,0,NULL));
755    wm->fnt->put_string(music_window->m_surf,0,1,"songs");
756  } else
757  {
758    wm->close_window(music_window);
759    music_window=NULL;
760  }*/
761}
762
763void dev_controll::toggle_bgw()
764{
765    if(backw)
766    {
767        backw_on = 1;
768        prop->setd("back x", backw->x);
769        prop->setd("back y", backw->y);
770        wm->close_window(backw);
771        backw = NULL;
772        return;
773    }
774
775    /* FIXME: shouldn't this be 1? */
776    backw_on = 0;
777    int maxh = (yres - 25) / (the_game->btile_height() / bg_scale);
778
779    /* FIXME: previous code had 1 instead of 0, investigate */
780    tile_picker *f_tp = new tile_picker(0, 0, DEV_BG_PICKER, SPEC_BACKTILE,
781                                        bg_scale, maxh, bg_w, NULL);
782    forew = wm->new_window(prop->getd("back x", -30), prop->getd("back y", 0),
783                           -1, -1, f_tp,symbol_str("l_bg"));
784}
785
786void dev_controll::toggle_search_window()
787{
788    if(search_window)
789    {
790        searchw_on = 1;
791        prop->setd("searchw x", search_window->x);
792        prop->setd("searchw y", search_window->y);
793        prop->set("search name", search_window->read(ID_SEARCH_TEXT));
794        wm->close_window(search_window);
795        search_window = NULL;
796        search_object = NULL;
797        return;
798    }
799
800    int bw = cache.img(dev_forward)->Size().x;
801    /* FIXME: previous code had 1,1 instead of 0,0 -- investigate */
802    search_window = wm->new_window(prop->getd("searchw x", -30),
803                                   prop->getd("searchw y", 0), -1, -1,
804        new text_field(0, 0, ID_SEARCH_TEXT, "object name>",
805                       "***************************",
806                       prop->get("search name", ""),
807        new button(bw, wm->font()->height() + 5, ID_SEARCH_BACKWARD,
808                   cache.img(dev_backward),
809        new button(bw * 3, wm->font()->height() + 5, ID_SEARCH_FOREWARD,
810                   cache.img(dev_forward), NULL))), "SEARCH");
811
812    /* FIXME: shouldn't this be 1? */
813    searchw_on = 0;
814}
815
816int open_owin=0,open_fwin=0,open_bwin=0,start_edit=0,start_nodelay=0,start_doubled=0,start_mem=0;
817
818
819int get_option(char const *name);
820
821
822void dev_init(int argc, char **argv)
823{
824  scale_mult=1;
825  scale_div=1;
826  dev=0;
827  int i;
828  prop=new property_manager;
829  prop->load("defaults.prp");
830
831  for (i=1; i<argc; i++)
832  {
833    if (!strcmp(argv[i],"-edit"))
834    {
835      dev|=EDIT_MODE;
836      start_edit=1;
837      start_running=1;
838      disable_autolight=1;
839      if (get_option("-2"))
840      {
841        printf("%s\n",symbol_str("no2"));
842        exit(0);
843      }
844    }
845    else if (!strcmp(argv[i],"-fwin"))
846      open_fwin=1;
847    else if (!strcmp(argv[i],"-show_mem"))
848      start_mem=1;
849    else if (!strcmp(argv[i],"-bwin"))
850      open_bwin=1;
851    else if (!strcmp(argv[i],"-owin"))
852      open_owin=1;
853    else if (!strcmp(argv[i],"-nodelay"))
854      start_nodelay=1;
855// AK : NOTE: Commented this out as it causes a conflict
856/*    else if (!strcmp(argv[i],"-scale"))
857    {
858      i++;
859      scale_mult=atoi(argv[i++]);
860      scale_div=atoi(argv[i]);
861    }*/
862    else if (!strcmp(argv[i],"-f"))
863    {
864      i++;
865      strncpy(level_file, argv[i], sizeof(level_file) - 1);
866      level_file[sizeof(level_file) - 1] = '\0';
867    } else if (!strcmp(argv[i],"-2"))
868      start_doubled=1;
869    else if (!strcmp(argv[i],"-demo"))
870      demo_start=1;
871
872  }
873
874  if (get_option("-no_autolight"))
875    disable_autolight=0;
876
877  if ((get_option("-size") || get_option("-vmode")) && !start_edit)
878  {
879    printf("%s\n",symbol_str("no_hirez"));
880    exit(0);
881  }
882
883  fg_reversed=prop->getd("fg_reversed",0);
884  mouse_scrolling=prop->getd("mouse_scrolling",0);
885  palettes_locked=prop->getd("palettes_locked",0);
886  view_shift_disabled=prop->getd("view_shift_disabled",0);
887  fps_on=prop->getd("fps_on",0);
888  show_names=prop->getd("show_names",0);
889  raise_all=prop->getd("raise_all",0);
890}
891
892static pmenu *make_menu(int x, int y);
893
894
895dev_controll::dev_controll()
896{
897  area_win=NULL;
898  current_area=NULL;
899  fg_w=bg_w=1;
900  commandw=NULL;
901  bg_scale=fg_scale=1;
902  pal_wins=NULL;
903  total_pals=0;
904  state=DEV_SELECT;
905  aiw=NULL;
906  edit_light=NULL;
907  selected_light=NULL;
908
909  tbw=NULL;
910  modew=NULL;
911  link_object=NULL;
912  selected_object=NULL;
913  edit_object=NULL;
914  ai_object=NULL;
915  search_object = NULL;
916  oedit=NULL;
917  forew=NULL;
918  backw=NULL;
919  omenu=NULL;
920  ledit=NULL;
921  pmenu=NULL;
922  lightw=NULL;
923  search_window=NULL;
924  show_menu=NULL;
925  music_window=NULL;
926  ambw=NULL;
927  load_dev_icons();
928
929  if (open_owin) toggle_omenu();
930  if (open_fwin) toggle_fgw();
931  if (open_bwin) toggle_bgw();
932  if (start_nodelay) the_game->toggle_delay();
933  yellow=pal->find_closest(255,255,0);
934  if (start_edit)
935  {
936    the_game->load_level(level_file);
937    the_game->draw();
938  }
939
940  dev_console=new dev_term(50,18,this);
941  if (start_edit)
942    dev_menu=make_menu(0,yres-wm->font()->height()-5);
943
944  if (get_option("-nolight"))
945    dev=dev^DRAW_LIGHTS;
946}
947
948
949void dev_controll::set_state(int new_state)
950{
951  if (start_doubled && new_state==RUN_STATE && !small_render)
952    double_render();
953}
954
955void dev_controll::load_stuff()
956{
957  if (dev & EDIT_MODE)
958  {
959    char prog[100];
960    char const *cs;
961    strcpy(prog,"(compile-file \"edit.lsp\")");
962    cs=prog;
963    LObject *p = LObject::Compile(cs);
964    l_user_stack.push(p);
965    p->Eval();
966    l_user_stack.pop(1);
967    for (int i=0; i<total_pals; i++)
968      pal_wins[i]->close_window();
969  }
970
971}
972
973void dev_controll::do_command(char const *command, Event &ev)
974{
975  char fword[50];
976  char const *st;
977  int l,h,x,y,i;
978  if (command[0]=='(')            // is this a lisp command?
979  {
980    LObject::Compile(command)->Eval();
981    return ;
982  }
983
984  sscanf(command,"%s",fword);
985  for (st=command; *st && *st!=' '; st++);
986  if (*st) st++;
987  if (!strcmp(fword,"active"))
988  {
989    if (current_level && current_level->first_active_object())
990    {
991      game_object *o=current_level->first_active_object();
992      while (o)
993      {
994    dprintf("%s %d %d %d %d\n",object_names[o->otype],o->x,o->y,
995        figures[o->otype]->rangex,
996        figures[o->otype]->rangey
997        );
998    o=o->next_active;
999      }
1000    }
1001  }
1002
1003  if (!strcmp(fword,"clear_weapons"))
1004  {
1005    view *f=NULL;
1006    for (f=player_list; f; f=f->next)
1007    {
1008      int i;
1009      for (i=0; i<total_weapons; i++)
1010    f->weapons[i]=-1;
1011
1012      if (total_weapons)
1013        f->weapons[0]=0;
1014    }
1015  }
1016
1017  if (!strcmp(fword,"reload"))
1018  {
1019    if (current_level && player_list && player_list->focus)
1020    {
1021      edit_object=selected_object=NULL;
1022      int32_t cx=player_list->focus->x,cy=player_list->focus->y;
1023
1024      // save the old weapon array
1025      int32_t *w=(int32_t *)malloc(total_weapons*sizeof(int32_t));
1026      memcpy(w,player_list->weapons,total_weapons*sizeof(int32_t));
1027
1028      char tmp[100];
1029      strcpy(tmp,current_level->name());
1030      the_game->load_level(tmp);
1031      current_level->unactivate_all();
1032
1033      if (main_screen)  // don't draw if graphics haven't been setup yet.
1034        the_game->draw();
1035      player_list->reset_player();
1036      player_list->focus->x=cx;
1037      player_list->focus->y=cy;
1038
1039      memcpy(player_list->weapons,w,total_weapons*sizeof(int32_t));
1040      free(w);
1041
1042      the_game->need_refresh();
1043    }
1044  }
1045
1046  if (!strcmp(fword,"unchop"))
1047  {
1048    vec2i tile = the_game->GetBgTile(vec2i(dlastx, dlasty));
1049    if (tile.x>=0 && tile.y>=0)
1050    {
1051      if (sscanf(command,"%s%d%d",fword,&l,&h)==3)
1052      {
1053    dprintf("unchopped %dx%d to ",l,h);
1054    l=(l+the_game->btile_width()-1)/the_game->btile_width();
1055    h=(h+the_game->btile_height()-1)/the_game->btile_height();
1056    for (y=0,i=cur_bg; y<h; y++)
1057          for (x=0; x<l; x++)
1058            the_game->put_bg(tile.x+x,tile.y+y,i++);
1059    dprintf("%dx%d\n",l,h);
1060      } else dprintf(symbol_str("unchop1"));
1061
1062    }
1063  }
1064  if (!strcmp(fword,"center"))
1065  {
1066    view *v=the_game->first_view;
1067    for (; v; v=v->next)
1068    {
1069      v->pan_x=0;
1070      v->pan_y=0;
1071    }
1072    the_game->need_refresh();
1073  }
1074
1075  if (!strcmp(fword,"size"))
1076  {
1077    int l,w;
1078    if (sscanf(command,"%s%d%d",fword,&l,&w)==3)
1079    {
1080      current_level->set_size(l,w);
1081      dprintf("level is now %dx%d\n",l,w);
1082    } else dprintf(symbol_str("size1"));
1083
1084
1085  }
1086  if (!strcmp(fword,"name"))
1087  {
1088    while (*command && *command!=' ') command++;
1089    if (*command)
1090      current_level->set_name(command+1);
1091    dprintf(symbol_str("name_now"),current_level->name());
1092  }
1093  if (!strcmp(fword,"set_first_level"))
1094  {
1095    strcpy(level_file,st);
1096    dprintf("first level will be '%s'\n",level_file);
1097  }
1098
1099  if (!strcmp(fword,"load"))
1100  {
1101    if (!strcmp(st,"STARTING_LEVEL"))
1102      st=level_file;
1103
1104    dprintf("loading '%s'\n",st);
1105    the_game->load_level(st);
1106    current_level->unactivate_all();
1107
1108    the_game->need_refresh();
1109  }
1110
1111  if (!strcmp(fword,"mem"))
1112  {
1113    if (st[0])
1114      show_char_mem(st);
1115    else show_mem();
1116  }
1117
1118  if (!strcmp(fword,"esave"))
1119  {
1120    dprintf(symbol_str("esave"));
1121    save();
1122  }
1123
1124  if (!strcmp(fword,"delete"))
1125  {
1126    if (selected_object)
1127    {
1128      if (!(dev&EDIT_MODE) && current_level->is_attacker(selected_object))
1129        the_game->show_help(symbol_str("nd_player"));
1130      else
1131      {
1132    if (selected_object->controller())
1133      the_game->show_help(symbol_str("nd_player"));
1134    else
1135    {
1136      current_level->delete_object(selected_object);
1137      if (S_DELETE_SND>0) cache.sfx(S_DELETE_SND)->play(sfx_volume/2);
1138      selected_object=NULL;
1139    }
1140      }
1141    } else if (selected_light)
1142    {
1143      if (!edit_light)
1144      {
1145    if (current_level)
1146    {
1147          current_level->remove_light(selected_light);
1148      if (S_DELETE_SND>0) cache.sfx(S_DELETE_SND)->play(sfx_volume/2);
1149    }
1150    else
1151          delete_light(selected_light);
1152    selected_light=NULL;
1153      }
1154    } else the_game->show_help(symbol_str("d_nosel"));
1155    the_game->need_refresh();
1156  }
1157
1158  if (!strcmp(fword,"create"))
1159  {
1160    char oname[100];
1161    sscanf(command,"%s%s",fword,oname);       // read the type of object to create
1162    int x,t=-1;
1163    for (x=0; x<total_objects; x++)             // find the object type by name
1164       if (!strcmp(object_names[x],oname))
1165         t=x;
1166
1167    if (t>=0)                                 // did we find it?
1168    {
1169      vec2i pos = the_game->MouseToGame(vec2i(dlastx, dlasty));
1170      edit_object=create(t, pos.x, pos.y);
1171      current_level->add_object(edit_object);
1172      the_game->need_refresh();
1173      last_created_type=t;
1174    } else
1175    {
1176      sprintf(fword,"No such object type : %s\n",oname);
1177      the_game->show_help(fword);
1178    }
1179  }
1180
1181  if (!strcmp(fword,"move"))
1182  {
1183    if (selected_object)
1184      edit_object=selected_object;
1185
1186    if (edit_object)
1187      state=DEV_MOVE_OBJECT;
1188    else the_game->show_help("No object selected");
1189
1190  }
1191  if (!strcmp(fword,"move_light"))
1192  {
1193    if (selected_light)
1194      edit_light=selected_light;
1195
1196    if (edit_light)
1197      state=DEV_MOVE_LIGHT;
1198    else the_game->show_help("No light selected");
1199
1200  }
1201
1202
1203  if (!strcmp(fword,"clear_auto"))
1204  {
1205    int32_t i,j;
1206    for (i=0; i<current_level->foreground_width(); i++)
1207      for (j=0; j<current_level->foreground_height(); j++)
1208        current_level->clear_fg(i,j);
1209  }
1210
1211  if (!strcmp(fword,"fg_select"))
1212  {
1213    vec2i tile = the_game->GetFgTile(vec2i(dlastx, dlasty));
1214    if (tile.x >= 0 && tile.y >= 0 &&
1215        tile.x < current_level->foreground_width() &&
1216        tile.y < current_level->foreground_height())
1217    {
1218      cur_fg=current_level->get_fg(tile.x, tile.y);
1219      if (forew)
1220    ((tile_picker *)forew->read(DEV_FG_PICKER))->recenter(forew->m_surf);
1221      the_game->need_refresh();
1222    }
1223  }
1224
1225  if (!strcmp(fword,"toggle_fg_raise"))
1226  {
1227    vec2i tile = the_game->GetFgTile(vec2i(dlastx, dlasty));
1228    if (tile.x >= 0 && tile.y >= 0 &&
1229        tile.x < current_level->foreground_width() &&
1230        tile.y < current_level->foreground_height())
1231      current_level->fg_set_raised(tile.x, tile.y,!current_level->fg_raised(tile.x,tile.y));
1232  }
1233
1234  if (!strcmp(fword,"fg_add"))
1235  {
1236    int x;
1237    if (sscanf(st,"%d",&x))
1238    {
1239      cur_fg++;
1240      if (cur_fg<0) cur_fg=0;
1241      if (cur_fg>=nforetiles) cur_fg=nforetiles-1;
1242
1243      if (forew)
1244    ((tile_picker *)forew->read(DEV_FG_PICKER))->recenter(forew->m_surf);
1245    }
1246  }
1247
1248  if (!strcmp(fword,"restart"))
1249  {
1250    current_level->restart();
1251  }
1252  if (!strcmp(fword,"quit"))
1253  {
1254    the_game->end_session();
1255  }
1256
1257  if (!strcmp(fword,"to_front"))
1258  {
1259    game_object *which=selected_object;
1260    if (!selected_object) which=edit_object;
1261    if (which)
1262      current_level->to_front(which);
1263    else the_game->show_help(symbol_str("forward?"));
1264  }
1265
1266  if (!strcmp(fword,"to_back"))
1267  {
1268    game_object *which=selected_object;
1269    if (!selected_object) which=edit_object;
1270    if (which)
1271      current_level->to_back(which);
1272    else the_game->show_help(symbol_str("back?"));
1273  }
1274
1275  if (!strcmp(fword,"set_aitype"))
1276  {
1277    game_object *which=selected_object;
1278    if (!selected_object) which=edit_object;
1279    if (which)
1280    {
1281      int x;
1282      if (*st && sscanf(st,"%d",&x)!=EOF)
1283        which->change_aitype(x);
1284      else
1285      {
1286    switch (ev.key)
1287    {
1288      case '0' : which->change_aitype(0); break;
1289      case '1' : which->change_aitype(1); break;
1290      case '2' : which->change_aitype(2); break;
1291      case '3' : which->change_aitype(3); break;
1292      case '4' : which->change_aitype(4); break;
1293      case '5' : which->change_aitype(5); break;
1294      case '6' : which->change_aitype(6); break;
1295      case '7' : which->change_aitype(7); break;
1296      case '8' : which->change_aitype(8); break;
1297      case '9' : which->change_aitype(9); break;
1298      case ')' : which->change_aitype(10); break;
1299      case '!' : which->change_aitype(11); break;
1300      case '@' : which->change_aitype(12); break;
1301      case '#' : which->change_aitype(13); break;
1302      case '$' : which->change_aitype(14); break;
1303      case '%' : which->change_aitype(15); break;
1304      case '^' : which->change_aitype(16); break;
1305      case '&' : which->change_aitype(17); break;
1306      case '*' : which->change_aitype(18); break;
1307      case '(' : which->change_aitype(19); break;
1308    }
1309      }
1310      the_game->need_refresh();
1311    }
1312    else the_game->show_help(symbol_str("aitype"));
1313  }
1314}
1315
1316
1317void dev_controll::toggle_light_window()
1318{
1319    if(lightw)
1320    {
1321        prop->setd("light create x", lightw->x);
1322        prop->setd("light create y", lightw->y);
1323        prop->setd("light create w", atoi(lightw->read(DEV_LIGHTW)));
1324        prop->setd("light create h", atoi(lightw->read(DEV_LIGHTH)));
1325        prop->setd("light create r1", atoi(lightw->read(DEV_LIGHTR1)));
1326        prop->setd("light create r2", atoi(lightw->read(DEV_LIGHTR2)));
1327        wm->close_window(lightw);
1328        lightw = NULL;
1329        return;
1330    }
1331
1332    int bh = 16 + 6, bw = 20 + 6, th = wm->font()->height() + 4;
1333
1334    lightw = wm->new_window(prop->getd("light create x", 0),
1335                            prop->getd("light create y", 0), -1, -1,
1336        new button_box(0, 0, DEV_LIGHT_BUTTON_BOX, 1,
1337            new button(bw * 0, bh * 0, DEV_LIGHT0, cache.img(light_buttons[0]),
1338            new button(bw * 1, bh * 0, DEV_LIGHT1, cache.img(light_buttons[1]),
1339            new button(bw * 2, bh * 0, DEV_LIGHT2, cache.img(light_buttons[2]),
1340            new button(bw * 0, bh * 1, DEV_LIGHT3, cache.img(light_buttons[3]),
1341            new button(bw * 1, bh * 1, DEV_LIGHT4, cache.img(light_buttons[4]),
1342            new button(bw * 2, bh * 1, DEV_LIGHT5, cache.img(light_buttons[5]),
1343            new button(bw * 0, bh * 2, DEV_LIGHT6, cache.img(light_buttons[6]),
1344            new button(bw * 1, bh * 2, DEV_LIGHT7, cache.img(light_buttons[7]),
1345            new button(bw * 2, bh * 2, DEV_LIGHT8, cache.img(light_buttons[8]),
1346            new button(bw * 0, bh * 3, DEV_LIGHT9, cache.img(light_buttons[9]),
1347            new button(bw * 1, bh * 3, DEV_AMBIENT, cache.img(light_buttons[11]),
1348            NULL))))))))))),
1349        new text_field(0, bh * 4, DEV_LIGHTW, "W ", "******",
1350                       prop->getd("light create w", 0),
1351        new text_field(0, bh * 4 + th * 1, DEV_LIGHTH, "H ", "******",
1352                       prop->getd("light create h", 0),
1353        new text_field(0, bh * 4 + th * 2, DEV_LIGHTR1, "R1", "******",
1354                       prop->getd("light create r1", 1),
1355        new text_field(0, bh * 4 + th * 3, DEV_LIGHTR2, "R2", "******",
1356                       prop->getd("light create r2", 100), NULL))))),
1357        symbol_str("l_light"));
1358}
1359
1360void dev_controll::make_ai_window(game_object *o)
1361{
1362  ai_object=o;
1363  int th=wm->font()->height()+4,wl = 0, wh = 20;
1364  if (figures[o->otype]->total_fields)
1365  {
1366    int maxl=0;
1367    int i=0;
1368    for (; i<figures[o->otype]->total_fields; i++)
1369      if( strlen(figures[o->otype]->fields[i]->descript_name) > (unsigned)maxl )
1370        maxl=strlen(figures[o->otype]->fields[i]->descript_name);
1371
1372    int owh=wh;
1373    ifield *first=NULL,*last=NULL;
1374    for (i=0; i<figures[o->otype]->total_fields; i++)
1375    {
1376      char tmp[200];
1377      strcpy(tmp,figures[o->otype]->fields[i]->descript_name);
1378      for (int j=maxl-strlen(figures[o->otype]->fields[i]->descript_name); j; j--)
1379        strcat(tmp," ");
1380      int er;
1381      ifield *p=new text_field(wl,wh,ID_NULL,tmp,"######",
1382                   (double)o->get_var_by_name(figures[o->otype]->fields[i]->real_name,er),
1383                   NULL);
1384      if (last)
1385        last->next=p;
1386      else
1387        first=p;
1388      last=p;
1389      wh+=th;
1390    }
1391    aiw=wm->new_window(prop->getd("ai x",0),
1392               prop->getd("ai y",0),
1393               -1,-1,
1394       new button(wl,owh-20,DEV_AI_OK,cache.img(dev_ok),first),"ai");
1395
1396  }
1397  else
1398  {
1399    aiw=wm->new_window(prop->getd("ai x",0),
1400               prop->getd("ai y",0),
1401               -1,-1,
1402       new button(wl,wh-20,DEV_AI_OK,cache.img(dev_ok),
1403       new text_field(wl,wh+th*0, DEV_AI_XVEL,    symbol_str("ai_xvel"),"#####",(double)o->xvel(),
1404       new text_field(wl,wh+th*1, DEV_AI_YVEL,    symbol_str("ai_yvel"),"#####",(double)o->yvel(),
1405       new text_field(wl,wh+th*2, DEV_AI_XACEL,   symbol_str("ai_xacel"),"#####",(double)o->xacel(),
1406       new text_field(wl,wh+th*3, DEV_AI_YACEL,   symbol_str("ai_yacel"),"#####",(double)o->yacel(),
1407       new text_field(wl,wh+th*4, DEV_AI_STTIME,  symbol_str("ai_stime"),"####",(double)o->aistate_time(),
1408       new text_field(wl,wh+th*5, DEV_AI_GRAVITY, symbol_str("ai_gravity"),"####",(double)o->gravity(),
1409       new text_field(wl,wh+th*6, DEV_AI_HEALTH,  symbol_str("ai_health"),"####",(double)o->hp(),
1410       new text_field(wl,wh+th*7, DEV_AI_MORPHPR, symbol_str("ai_morph"),"####",(double)o->mp(),
1411       new text_field(wl,wh+th*8, DEV_AI_TYPE,    symbol_str("ai_type"),"####",(double)o->aitype(),
1412       new text_field(wl,wh+th*9,DEV_AI_STATE,    symbol_str("ai_state"),"####",(double)o->aistate(),
1413       new text_field(wl,wh+th*10,DEV_AI_FADE,    symbol_str("ai_fade"),"####",(double)o->fade_count(),
1414              NULL)))))))))))),"ai");
1415  }
1416
1417  wm->grab_focus(aiw);
1418}
1419
1420void dev_controll::notify_deleted_light(light_source *l)
1421{
1422  if (l==edit_light)
1423  {
1424    if (ledit)
1425    {
1426      prop->setd("ledit x",ledit->x);
1427      prop->setd("ledit y",ledit->y);
1428      wm->close_window(ledit); ledit=NULL;
1429    }
1430    edit_light=NULL;
1431  }
1432  if (l==selected_light)
1433    selected_light=NULL;
1434}
1435
1436void dev_controll::notify_deleted_object(game_object *o)
1437{
1438  if (o==edit_object)
1439  {
1440    state=DEV_SELECT;
1441    close_oedit_window();
1442  }
1443
1444  if (o==ai_object)
1445    close_ai_window();
1446  if (o==search_object)
1447  { if (search_window)
1448      toggle_search_window();
1449    search_object=NULL;
1450  }
1451  if (o==link_object)
1452    link_object=NULL;
1453  if (o==selected_object)
1454  {
1455    selected_object=NULL;
1456    state=DEV_SELECT;
1457  }
1458
1459}
1460
1461void dev_controll::close_ai_window()
1462{
1463  if (aiw)
1464  {
1465    game_object *o=ai_object;
1466    int32_t x;
1467    if (o)
1468    {
1469      if (figures[o->otype]->total_fields)
1470      {
1471    ifield *f=aiw->inm->get(DEV_AI_OK)->next;
1472    for (int i=0; i<figures[o->otype]->total_fields; i++)
1473    {
1474      x=atoi(f->read());
1475      char *v=figures[o->otype]->fields[i]->real_name;
1476      int er;
1477      if (o->get_var_by_name(v,er)!=x)
1478      o->set_var_by_name(v,x);
1479      f=f->next;
1480    }
1481      }
1482      else
1483      {
1484    x=atoi(aiw->read(DEV_AI_XVEL)); if (x!=o->xvel()) o->set_xvel(x);
1485    x=atoi(aiw->read(DEV_AI_YVEL)); if (x!=o->yvel()) o->set_yvel(x);
1486
1487    x=atoi(aiw->read(DEV_AI_XACEL)); if (x!=o->xacel()) o->set_xacel(x);
1488    x=atoi(aiw->read(DEV_AI_YACEL)); if (x!=o->yacel()) o->set_yacel(x);
1489
1490    x=atoi(aiw->read(DEV_AI_STTIME)); if (x!=o->aistate_time()) o->set_aistate_time(x);
1491    x=atoi(aiw->read(DEV_AI_GRAVITY)); if (x!=o->gravity()) o->set_gravity(x);
1492
1493    x=atoi(aiw->read(DEV_AI_HEALTH)); if (x!=o->hp()) o->set_hp(x);
1494    x=atoi(aiw->read(DEV_AI_MORPHPR)); if (x!=o->mp()) o->set_mp(x);
1495
1496    x=atoi(aiw->read(DEV_AI_TYPE)); if (x!=o->aitype()) o->set_aitype(x);
1497    x=atoi(aiw->read(DEV_AI_STATE)); if (x!=o->aistate()) o->set_aistate(x);
1498    x=atoi(aiw->read(DEV_AI_FADE)); if (x!=o->fade_count()) o->set_fade_count(x);
1499      }
1500    }
1501    prop->setd("ai x",aiw->x);
1502    prop->setd("ai y",aiw->y);
1503    wm->close_window(aiw);
1504    aiw=NULL;
1505    ai_object=NULL;
1506    the_game->need_refresh();
1507  }
1508}
1509
1510
1511void dev_controll::area_handle_input(Event &ev)
1512{
1513
1514  if (ev.type==EV_MOUSE_BUTTON && ev.mouse_button)
1515  {
1516    vec2i pos = the_game->MouseToGame(vec2i(last_demo_mx, last_demo_my));
1517    if (!current_level) return ;
1518    current_area=current_level->area_list=new area_controller(pos.x, pos.y,
1519                                  the_game->ftile_width(),
1520                                  the_game->ftile_height(),
1521                                  current_level->area_list);
1522    the_game->need_refresh();
1523    state=DEV_DRAG_AREA_BOTTOM;
1524  }
1525}
1526
1527void dev_controll::close_area_win(int read_values)
1528{
1529  if (area_win)
1530  {
1531    prop->setd("area_box x",area_win->x);
1532    prop->setd("area_box y",area_win->y);
1533
1534    if (current_area && read_values)
1535    {
1536      current_area->ambient=atoi(area_win->read(DEV_AREA_AMBIENT));
1537      current_area->ambient_speed=atoi(area_win->read(DEV_AREA_AMBIENT_SPEED));
1538      current_area->view_xoff=atoi(area_win->read(DEV_AREA_VIEW_XOFF));
1539      current_area->view_yoff=atoi(area_win->read(DEV_AREA_VIEW_YOFF));
1540      current_area->view_xoff_speed=atoi(area_win->read(DEV_AREA_VIEW_XOFF_SPEED));
1541      current_area->view_yoff_speed=atoi(area_win->read(DEV_AREA_VIEW_YOFF_SPEED));
1542    }
1543    wm->close_window(area_win);
1544    area_win=NULL;
1545  }
1546}
1547
1548void dev_controll::pick_handle_input(Event &ev)
1549{
1550  area_controller *find=NULL;
1551  int find_top=0;
1552  if (!current_level) return;
1553  if (ev.type==EV_MOUSE_BUTTON && ev.mouse_button)
1554  {
1555    int32_t mx=last_demo_mx,my=last_demo_my;
1556    view *v = the_game->GetView(vec2i(mx, my));
1557    for (area_controller *a=current_level->area_list; a; a=a->next)
1558    {
1559      vec2i pos1 = the_game->GameToMouse(vec2i(a->x, a->y), v);
1560      vec2i pos2 = the_game->GameToMouse(vec2i(a->x + a->w, a->y + a->h), v);
1561      if (abs(pos1.x - mx) < 2 && abs(pos1.y - my) < 2)
1562      { find = a; find_top = 1; }
1563      else if (abs(pos2.x - mx) < 2 && abs(pos2.y - my) < 2)
1564      { find = a; find_top = 0; }
1565    }
1566
1567    time_marker now;
1568    int dc=now.diff_time(&last_area_click)<0.5;
1569    last_area_click.get_time();
1570    if (find && current_area && dc)
1571    {
1572      if (area_win) close_area_win(0);
1573      int wl=0,wh=0,th=wm->font()->height()+12,bw=cache.img(dev_ok)->Size().x+10;
1574      area_win=wm->new_window(prop->getd("area_box x",0),
1575                  prop->getd("area_box y",0),
1576                  -1,-1,
1577
1578                  new button(wl+bw*0,wh-8,DEV_AREA_OK,cache.img(dev_ok),
1579                  new button(wl+bw*1,wh-8,DEV_AREA_DELETE,cache.img(dev_del),
1580
1581                  new text_field(wl,wh+th*1,DEV_AREA_AMBIENT,         symbol_str("a_ambient"),"******",current_area->ambient,
1582                              new text_field(wl,wh+th*2,DEV_AREA_AMBIENT_SPEED,   symbol_str("a_aspeed"),"******",current_area->ambient_speed,
1583                              new text_field(wl,wh+th*3,DEV_AREA_VIEW_XOFF,       symbol_str("a_view_xoff"),"******",current_area->view_xoff,
1584                              new text_field(wl,wh+th*4,DEV_AREA_VIEW_YOFF,       symbol_str("a_view_yoff"),"******",current_area->view_yoff,
1585                              new text_field(wl,wh+th*5,DEV_AREA_VIEW_XOFF_SPEED, symbol_str("a_view_xspd"),"******",current_area->view_xoff_speed,
1586                              new text_field(wl,wh+th*6,DEV_AREA_VIEW_YOFF_SPEED, symbol_str("a_view_yspd"),"******",current_area->view_yoff_speed,
1587                         NULL)))))))));
1588    } else if (find)
1589    {
1590      current_area=find;
1591      current_area->active=1;
1592      if (find_top)
1593      state=DEV_DRAG_AREA_TOP;
1594      else state=DEV_DRAG_AREA_BOTTOM;
1595      the_game->need_refresh();
1596    } else if (current_area)
1597    {
1598      current_area->active=0;
1599      current_area=NULL;
1600      the_game->need_refresh();
1601    }
1602  }
1603}
1604
1605void dev_controll::close_oedit_window()
1606{
1607  if (oedit)
1608  {
1609    prop->setd("oedit x",oedit->x);
1610    prop->setd("oedit y",oedit->y);
1611    wm->close_window(oedit);
1612    oedit=NULL;
1613    edit_object=NULL;
1614  }
1615}
1616
1617int screen_shot_on=1;
1618int sshot_fcount=-1;
1619
1620void dev_controll::handle_event(Event &ev)
1621{
1622  int32_t x,y;
1623  if (link_object && (dlastx!=last_link_x || dlasty!=last_link_y))
1624  {
1625    last_link_x=dlastx;
1626    last_link_y=dlasty;
1627    the_game->need_refresh();
1628  }
1629
1630  if (dev_menu && dev_menu->handle_event(ev,main_screen)) return ;
1631
1632  if (!current_level) return ;
1633
1634  for (x=0; x<total_pals; x++)
1635    pal_wins[x]->handle_event(ev);
1636  if (ev.type==EV_MOUSE_MOVE)
1637  {
1638    dlastx=last_demo_mx;
1639    dlasty=last_demo_my;
1640  }
1641  if (dev_console && dev_console->handle_event(ev))
1642    return;
1643
1644  if (ev.type==EV_KEY && ev.key==JK_F2)
1645    write_PCX(main_screen,pal,"scrnshot.pcx");
1646  else if (ev.type==EV_KEY && ev.key==JK_F3)
1647  {
1648    char name[100];
1649    sprintf(name,"shot%04d.pcx",screen_shot_on++);
1650    write_PCX(main_screen,pal,name);
1651  } else if (ev.type==EV_KEY && ev.key==JK_F5)
1652  {
1653    if (sshot_fcount!=-1)
1654    {
1655      sshot_fcount=-1;
1656      the_game->show_help(symbol_str("seqs_off"));
1657    }
1658    else
1659    {
1660      sshot_fcount=0;
1661      the_game->show_help(symbol_str("seqs_on"));
1662    }
1663  }
1664
1665  switch (state)
1666  {
1667    case DEV_MOUSE_RELEASE :
1668    {
1669      if (!ev.mouse_button)
1670        state=DEV_SELECT;
1671    } break;
1672
1673    case DEV_CREATE_OBJECT :
1674    {
1675      if (!ev.mouse_button)
1676        state=DEV_MOVE_OBJECT;
1677    } break;
1678
1679
1680    case DEV_MOVE_OBJECT :
1681    {
1682      if (!edit_object)
1683      { state=DEV_SELECT; }
1684      else
1685      {
1686    if (ev.type==EV_MOUSE_MOVE)
1687    {
1688      vec2i pos = the_game->MouseToGame(vec2i(last_demo_mx, last_demo_my));
1689      edit_object->x = snap_x(pos.x);
1690      edit_object->y = snap_y(pos.y);
1691      the_game->need_refresh();
1692    }
1693    else if (ev.mouse_button==1 && ev.window==NULL)
1694    {
1695      state=DEV_MOUSE_RELEASE;
1696      selected_object=edit_object=NULL;
1697    }
1698    if (ev.window==NULL && ev.type==EV_KEY && ev.key=='d')
1699    {
1700      int32_t xv=0,yv=100;
1701      edit_object->try_move(edit_object->x,edit_object->y,xv,yv,1);
1702      edit_object->y+=yv;
1703      state=DEV_SELECT;
1704      selected_object=edit_object=NULL;
1705    }
1706      }
1707    } break;
1708
1709
1710    case DEV_MOVE_LIGHT :
1711    {
1712      if (edit_light)
1713      {
1714    if (ev.type==EV_MOUSE_MOVE)
1715    {
1716      vec2i pos = the_game->MouseToGame(vec2i(last_demo_mx, last_demo_my));
1717      edit_light->x = snap_x(pos.x);
1718      edit_light->y = snap_y(pos.y);
1719
1720      edit_light->calc_range();
1721      the_game->need_refresh();
1722    } else if (ev.type==EV_KEY)
1723    {
1724      int rd=0;
1725      switch (ev.key)
1726      {
1727        case '+' :
1728        {
1729          if (edit_light->type==9)
1730          {
1731        if (edit_light->inner_radius<64)
1732        { edit_light->inner_radius++; rd=1; }
1733          } else { edit_light->outer_radius++; rd=1; }
1734        } break;
1735        case '-' :
1736        {
1737          if (edit_light->type==9)
1738          {
1739        if (edit_light->inner_radius>0)
1740        { edit_light->inner_radius--; rd=1; }
1741          } else if (edit_light->outer_radius>edit_light->inner_radius+1)
1742          { edit_light->outer_radius--; rd=1; }
1743        } break;
1744        case JK_RIGHT :
1745        {
1746          if (edit_light->type==9)
1747          { edit_light->xshift++; rd=1; }
1748          else if (edit_light->xshift>0)
1749          { edit_light->xshift--; rd=1; }
1750        } break;
1751        case JK_LEFT :
1752        {
1753          if (edit_light->type==9)
1754          {
1755        if (edit_light->xshift>1)
1756        { edit_light->xshift--; rd=1; }
1757          }
1758          else
1759          { edit_light->xshift++; rd=1; }
1760        } break;
1761        case JK_UP :
1762        {
1763          if (edit_light->type==9)
1764          { edit_light->yshift++; rd=1; }
1765          else if (edit_light->yshift>0)
1766          { edit_light->yshift--; rd=1; }
1767        } break;
1768        case JK_DOWN :
1769        {
1770          if (edit_light->type==9)
1771          {
1772        if (edit_light->yshift>1)
1773        { edit_light->yshift--; rd=1; }
1774          }
1775          else
1776          { edit_light->yshift++; rd=1; }
1777        } break;
1778
1779      }
1780      if (rd)
1781      {
1782        edit_light->calc_range();
1783        the_game->need_refresh();
1784      }
1785
1786    }
1787      }
1788
1789      if ((ev.mouse_button==1 && ev.window==NULL) || !edit_light)
1790        state=DEV_MOUSE_RELEASE;
1791    } break;
1792
1793
1794    case DEV_DRAG_AREA_BOTTOM :
1795    {
1796      if (current_area)
1797      {
1798    vec2i pos = the_game->MouseToGame(vec2i(last_demo_mx, last_demo_my));
1799    if (pos.x>current_area->x && pos.y>current_area->y)
1800    {
1801      if (pos.x-current_area->x!=current_area->w || pos.y-current_area->y!=current_area->h)
1802      {
1803        the_game->need_refresh();
1804        current_area->w=pos.x-current_area->x;
1805        current_area->h=pos.y-current_area->y;
1806      }
1807    }
1808    if (ev.type==EV_MOUSE_BUTTON && !ev.mouse_button)
1809    {
1810      current_area->active=0;
1811      state=DEV_SELECT;
1812    }
1813      }
1814    } break;
1815
1816    case DEV_DRAG_AREA_TOP :
1817    {
1818      if (current_area)
1819      {
1820    vec2i pos = the_game->MouseToGame(vec2i(last_demo_mx, last_demo_my));
1821    if (pos.x<current_area->x+current_area->w && pos.y<current_area->y+current_area->h)
1822    {
1823      if (pos.x!=current_area->x || pos.y!=current_area->y)
1824      {
1825        the_game->need_refresh();
1826        current_area->x=pos.x;
1827        current_area->y=pos.y;
1828      }
1829    }
1830    if (ev.type==EV_MOUSE_BUTTON && !ev.mouse_button)
1831    {
1832      current_area->active=0;
1833      state=DEV_SELECT;
1834    }
1835      }
1836    } break;
1837
1838    case DEV_SELECT :
1839    {
1840      if (dev&EDIT_MODE)
1841      {
1842    game_object *old=selected_object;
1843    selected_object=NULL;
1844    if (ev.window==NULL)
1845    {
1846      vec2i pos = the_game->MouseToGame(vec2i(last_demo_mx, last_demo_my));
1847
1848      if (!(dev & MAP_MODE))
1849      {
1850        if (dev&DRAW_PEOPLE_LAYER)
1851              selected_object=current_level->find_object(pos.x, pos.y);
1852        light_source *old_light=selected_light;
1853        selected_light = selected_object ? NULL : find_light(pos.x, pos.y);
1854        if (selected_light!=old_light)
1855          the_game->need_refresh();
1856      } else { selected_light=NULL; }
1857
1858      if (edit_mode==ID_DMODE_DRAW)
1859      {
1860        // FIXME: there is a bug here, the two if conditionals are the same
1861        if (ev.mouse_button==1 && !selected_object && !selected_light)
1862        {
1863          vec2i tile = the_game->GetFgTile(vec2i(last_demo_mx, last_demo_my));
1864          if (tile.x>=0 && tile.y>=0 && tile.x<current_level->foreground_width() &&
1865          tile.y<current_level->foreground_height())
1866          current_level->put_fg(tile.x,tile.y,raise_all ? make_above_tile(cur_fg) : cur_fg);
1867          the_game->need_refresh();
1868        } else if (ev.mouse_button==1 && !selected_object && !selected_light)
1869        {
1870          vec2i tile = the_game->GetBgTile(vec2i(last_demo_mx, last_demo_my));
1871          if (tile.x>=0 && tile.y>=0 && tile.x<current_level->background_width() &&
1872          tile.y<current_level->background_height())
1873          current_level->put_bg(tile.x,tile.y,cur_fg);
1874          the_game->need_refresh();
1875        }
1876      } else if (edit_mode==ID_DMODE_AREA)
1877        area_handle_input(ev);
1878      else if (edit_mode==ID_DMODE_PICK)
1879        pick_handle_input(ev);
1880    }
1881
1882    if (old!=selected_object)
1883        the_game->need_refresh();
1884
1885
1886    if (ev.mouse_button)
1887    {
1888      if (selected_object)
1889      {
1890        if (edit_object && edit_object!=selected_object)
1891             edit_object->add_object(selected_object);
1892
1893        if (oedit)
1894          close_oedit_window();
1895
1896        int bw=20+6,bh=16+6;
1897
1898        oedit=wm->new_window(prop->getd("oedit x",0),
1899                 prop->getd("oedit y",0),
1900                 -1,-1,new button_box(0,0,ID_NULL,1,
1901        new button(bw*0,0,DEV_OEDIT_OK,cache.img(dev_ok),
1902        new button(bw*1,0,DEV_OEDIT_MOVE,cache.img(dev_move),
1903        new button(bw*2,0,DEV_OEDIT_FRONT,cache.img(dev_front),
1904            new button(bw*3,0,DEV_OEDIT_BACK,cache.img(dev_back),
1905            new button(bw*4,0,DEV_OEDIT_COPY,cache.img(dev_copy),
1906        new button(bw*0,bh*1,DEV_OEDIT_DELETE,cache.img(dev_del),
1907               NULL)))))),
1908           new button(bw*5,bh*0,DEV_OEDIT_AI,cache.img(dev_ai),
1909
1910           new button_box(bw*1,bh*1,DEV_OEDIT_CHAR_BOX,0,
1911           new button(bw*1,bh*1,DEV_OEDIT_LEFT,cache.img(dev_char_left),
1912           new button(bw*2,bh*1,DEV_OEDIT_RIGHT,cache.img(dev_char_right),NULL)),
1913
1914           new button(bw*3,bh*1,DEV_OBJECTS_DELETE,cache.img(dev_objects),
1915           new button(bw*4,bh*1,DEV_LIGHTS_DELETE,cache.img(dev_lights),NULL))))),
1916                 symbol_str("l_EDIT"));
1917
1918
1919        edit_object=selected_object;
1920      } else if (selected_light)
1921      {
1922        if (ledit)
1923        {
1924          prop->setd("ledit x",ledit->x);
1925          prop->setd("ledit x",ledit->y);
1926          wm->close_window(ledit);
1927        }
1928        int bw=20+6,bh=16+6,th=wm->font()->height()+4;
1929        edit_light=selected_light;
1930        if (edit_object)
1931        {
1932          edit_object->add_light(edit_light);
1933          edit_light->known=1;
1934        }
1935        ledit=wm->new_window(prop->getd("ledit x",0),
1936                 prop->getd("ledit y",0),
1937                 -1,-1,
1938              new button_box(0,0,ID_NULL,1,
1939                   new button(bw*0,0,DEV_LEDIT_OK,cache.img(dev_ok),
1940               new button(bw*1,0,DEV_LEDIT_MOVE,cache.img(dev_move),
1941                  new button(bw*2,0,DEV_LEDIT_COPY,cache.img(dev_copy),
1942            new button(bw*3,0,DEV_LEDIT_DEL,cache.img(dev_del),NULL)))),
1943            new text_field(0,bh,DEV_LEDIT_W,      "W ","******",edit_light->xshift,
1944            new text_field(0,bh+th*1,DEV_LEDIT_H, "H ","******",edit_light->yshift,
1945          new text_field(0,bh+th*2,DEV_LEDIT_R1,"R1","******",(int)(edit_light->inner_radius),
1946         new text_field(0,bh+th*3,DEV_LEDIT_R2,"R2","******",(int)(edit_light->outer_radius),
1947                   NULL))))));
1948      }
1949      else if (ev.window==NULL)
1950      {
1951        if (dlastx>=0 && dlasty>=0 && edit_mode==ID_DMODE_DRAW)
1952        {
1953          if ((dev & DRAW_FG_LAYER) && ev.mouse_button==1)
1954          {
1955        vec2i tile = the_game->GetFgTile(vec2i(last_demo_mx, last_demo_my));
1956        if (tile.x>=0 && tile.y>=0 && tile.x<current_level->foreground_width() &&
1957            tile.y<current_level->foreground_height())
1958        the_game->put_fg(tile.x,tile.y,raise_all ? make_above_tile(cur_fg) : cur_fg);
1959          }
1960          if ((dev & DRAW_BG_LAYER) && ev.mouse_button==2)
1961          {
1962        vec2i tile = the_game->GetBgTile(vec2i(last_demo_mx, last_demo_my));
1963        if (tile.x>=0 && tile.y>=0 && tile.x<current_level->background_width() &&
1964            tile.y<current_level->background_height())
1965        the_game->put_bg(tile.x,tile.y,cur_bg);
1966          }
1967        }
1968      }
1969    }
1970      }
1971    }
1972    default:
1973      break;
1974  }
1975
1976  switch (ev.type)
1977  {
1978    case EV_MESSAGE :
1979    {
1980      switch (ev.message.id)
1981      {
1982    case ID_DMODE_DRAW :
1983    case ID_DMODE_PICK :
1984    case ID_DMODE_FILL :
1985    case ID_DMODE_LINE :
1986    case ID_DMODE_RECT :
1987    case ID_DMODE_BAR  :
1988    case ID_DMODE_AREA :
1989    {
1990      edit_mode=ev.message.id;
1991    } break;
1992/*    case ID_ENLARGE_RENDER :
1993    {
1994      if (!small_render)
1995        double_render();
1996      else
1997        single_render();
1998
1999      view_shift_disabled=!view_shift_disabled;
2000    } break; */
2001
2002    case ID_SEARCH :
2003    {
2004      toggle_search_window();
2005    } break;
2006    case ID_SEARCH_FOREWARD :
2007    { search_forward();
2008    } break;
2009    case ID_SEARCH_BACKWARD :
2010    { search_forward();
2011    } break;
2012    case ID_CANCEL :
2013    {
2014      if (mess_win)
2015      {
2016        wm->close_window(mess_win);
2017        mess_win=NULL;
2018      } break;
2019    } break;
2020    case ID_LEVEL_LOAD :
2021    {
2022      if (!mess_win)
2023      {
2024        mess_win=file_dialog(symbol_str("level_name"),current_level ? current_level->name() : "",
2025                 ID_LEVEL_LOAD_OK,symbol_str("ok_button"),ID_CANCEL,symbol_str("cancel_button"),
2026                 symbol_str("FILENAME"),ID_MESS_STR1);
2027        wm->grab_focus(mess_win);
2028      }
2029    } break;
2030    case ID_LEVEL_LOAD_OK :
2031    {
2032      char cmd[100];
2033      sprintf(cmd,"load %s",mess_win->read(ID_MESS_STR1));
2034      dev_cont->do_command(cmd,ev);
2035      wm->Push(new Event(ID_CANCEL,NULL));        // close window
2036    } break;
2037    case ID_GAME_SAVE :
2038    {
2039      current_level->save("savegame.spe",1);
2040      the_game->show_help(symbol_str("saved_game"));
2041      the_game->need_refresh();
2042    } break;
2043    case ID_LEVEL_SAVE :
2044    { if (current_level)
2045      {
2046        if (current_level->save(current_level->name(),0))
2047        {
2048          char msg[100];
2049          sprintf(msg,symbol_str("saved_level"),current_level->name());
2050          the_game->show_help(msg);
2051          the_game->need_refresh();
2052        }
2053      }
2054      else the_game->show_help("no current level, cannot save");
2055    } break;
2056    case ID_LEVEL_SAVEAS :
2057    {
2058      if (!mess_win)
2059      {
2060        mess_win=file_dialog(symbol_str("saveas_name"),current_level ? current_level->name() : "untitled.spe",
2061                   ID_LEVEL_SAVEAS_OK,symbol_str("ok_button"),
2062                 ID_CANCEL,symbol_str("cancel_button"),
2063                 symbol_str("FILENAME"),ID_MESS_STR1);
2064        wm->grab_focus(mess_win);
2065      }
2066    } break;
2067    case ID_LEVEL_SAVEAS_OK :
2068    {
2069      if (current_level)
2070      {
2071        current_level->set_name(mess_win->read(ID_MESS_STR1));
2072        wm->Push(new Event(ID_CANCEL,NULL));        // close window after save
2073        wm->Push(new Event(ID_LEVEL_SAVE,NULL));
2074      }
2075    } break;
2076    case ID_EDIT_SAVE :
2077    {
2078      do_command("esave",ev);
2079      the_game->show_help(symbol_str("edit_saved"));
2080    } break;
2081    case ID_CACHE_PROFILE :
2082    {
2083      if (current_level && !cache.prof_is_on())
2084      {
2085        cache.prof_init();
2086        the_game->show_help("Cache profiling is now on.");
2087      }
2088      else the_game->show_help("Cache profiling is already on!");
2089    } break;
2090
2091    case ID_CACHE_PROFILE_END :  // ask the user for a file name to save as
2092    {
2093      if (cache.prof_is_on())
2094      {
2095        cache.prof_uninit();
2096        the_game->show_help(symbol_str("prof_off"));
2097      } else the_game->show_help(symbol_str("prof"));
2098    } break;
2099
2100    case ID_LEVEL_NEW :
2101    {
2102      if (!mess_win)
2103      {
2104        mess_win=wm->new_window(xres/2,yres/2,-1,-1,
2105               new button(10,20,ID_LEVEL_NEW_OK,symbol_str("YES"),
2106                        new button(40,20,ID_CANCEL,symbol_str("NO"),
2107          new info_field(0,0,ID_NULL,symbol_str("sure?"),NULL))),symbol_str("New?"));
2108        wm->grab_focus(mess_win);
2109      }
2110    } break;
2111    case ID_LEVEL_NEW_OK :
2112    {
2113      wm->Push(new Event(ID_CANCEL,NULL));  // close_window
2114      if (current_level)
2115        delete current_level;
2116      current_level=new level(100,100,"untitled.spe");
2117    } break;
2118    case ID_LEVEL_RESIZE :
2119    {
2120      if (!mess_win)
2121      {
2122        int h=wm->font()->height()+8;
2123        mess_win=wm->new_window(xres/2,yres/2,-1,-1,
2124            new text_field(0,h*0,ID_MESS_STR1,symbol_str("width_"),"****",
2125                   current_level ? current_level->foreground_width() : 100,
2126            new text_field(0,h*1,ID_MESS_STR2,symbol_str("height_"),"****",
2127                   current_level ? current_level->foreground_height() : 100,
2128                   new button(10,h*4,ID_LEVEL_RESIZE_OK,symbol_str("ok_button"),
2129                   new button(40,h*4,ID_CANCEL,symbol_str("cancel_button"),NULL)))),symbol_str("_scroll"));
2130      }
2131    } break;
2132    case ID_LEVEL_RESIZE_OK :
2133    {
2134      if (current_level)
2135      {
2136        current_level->set_size(atoi(mess_win->read(ID_MESS_STR1)),
2137                    atoi(mess_win->read(ID_MESS_STR2)));
2138      } else the_game->show_help("Create a level first!");
2139      wm->Push(new Event(ID_CANCEL,NULL));  // close_window
2140    } break;
2141
2142    case ID_SUSPEND :
2143    {
2144      dev^=SUSPEND_MODE;
2145      if (dev&SUSPEND_MODE)
2146        the_game->show_help(symbol_str("suspend_on"));
2147      else
2148         the_game->show_help(symbol_str("suspend_off"));
2149    } break;
2150    case ID_PLAY_MODE :
2151    {
2152      dev^=EDIT_MODE;
2153    } break;
2154    case ID_QUIT :
2155    {
2156      if (confirm_quit())
2157        do_command("quit",ev);
2158    } ;
2159    case ID_TOGGLE_MAP :
2160    {
2161      if (dev&MAP_MODE) dev-=MAP_MODE;
2162      else dev|=MAP_MODE;
2163      the_game->need_refresh();
2164    } break;
2165    case ID_TOGGLE_LIGHT :
2166    {
2167      dev^=DRAW_LIGHTS;
2168      the_game->need_refresh();
2169    } break;
2170    case ID_RECORD_DEMO :
2171    {
2172      if (!mess_win)
2173      {
2174        int h=wm->font()->height()+8;
2175        mess_win=wm->new_window(xres/2,yres/2,-1,-1,
2176            new text_field(0,h*0,ID_RECORD_DEMO_FILENAME,
2177                   "demo filename","*******************",
2178                   "demo.dat",
2179                   new button(10,h*2,ID_RECORD_DEMO_OK,symbol_str("ok_button"),
2180                   new button(40,h*2,ID_CANCEL,symbol_str("cancel_button"),NULL))));
2181      }
2182    } break;
2183
2184        case ID_RECORD_DEMO_OK :
2185    {
2186      demo_man.set_state(demo_manager::RECORDING,mess_win->read(ID_RECORD_DEMO_FILENAME));
2187      wm->Push(new Event(ID_CANCEL,NULL));        // close window
2188    } break;
2189
2190    case ID_PLAY_DEMO :
2191    {
2192      if (!mess_win)
2193      {
2194        int h=wm->font()->height()+8;
2195        mess_win=wm->new_window(xres/2,yres/2,-1,-1,
2196            new text_field(0,h*0,ID_PLAY_DEMO_FILENAME,
2197                   "demo filename","*******************",
2198                   "demo.dat",
2199                   new button(10,h*2,ID_PLAY_DEMO_OK,symbol_str("ok_button"),
2200                   new button(40,h*2,ID_CANCEL,symbol_str("cancel_button"),NULL))));
2201      }
2202    } break;
2203
2204        case ID_PLAY_DEMO_OK :
2205    {
2206      demo_man.set_state(demo_manager::PLAYING,mess_win->read(ID_PLAY_DEMO_FILENAME));
2207      wm->close_window(mess_win);
2208      mess_win=NULL;
2209    } break;
2210
2211    case ID_SET_SCROLL :
2212    {
2213      if (!mess_win)
2214      {
2215        int h=wm->font()->height()+8;
2216        mess_win=wm->new_window(xres/2,yres/2,-1,-1,
2217            new text_field(0,h*0,ID_MESS_STR1,symbol_str("x_mul"),"****",bg_xmul,
2218            new text_field(0,h*1,ID_MESS_STR2,symbol_str("x_div"),"****",bg_xdiv,
2219            new text_field(0,h*2,ID_MESS_STR3,symbol_str("y_mul"),"****",bg_ymul,
2220            new text_field(0,h*3,ID_MESS_STR4,symbol_str("y_div"),"****",bg_ydiv,
2221                   new button(10,h*4,ID_SET_SCROLL_CHECK,symbol_str("ok_button"),
2222                   new button(40,h*4,ID_CANCEL,symbol_str("cancel_button"),NULL)))))),symbol_str("_scroll"));
2223      }
2224    } break;
2225    case ID_SET_SCROLL_CHECK :
2226    {
2227      int tbg_xmul=atoi(mess_win->read(ID_MESS_STR1));
2228      int tbg_xdiv=atoi(mess_win->read(ID_MESS_STR2));
2229      int tbg_ymul=atoi(mess_win->read(ID_MESS_STR3));
2230      int tbg_ydiv=atoi(mess_win->read(ID_MESS_STR4));
2231
2232      if ( (((float)tbg_xmul/(float)tbg_xdiv) < ((float)bg_xmul/(float)bg_xdiv)) ||
2233          (((float)tbg_ymul/(float)tbg_ydiv) < ((float)bg_ymul/(float)bg_ydiv)))
2234      {
2235        int h=wm->font()->height()+8;
2236
2237        warn_win=wm->new_window(xres/2-40,yres/2-40,-1,-1,
2238                  new info_field(0,0,ID_NULL,
2239                      symbol_str("back_loss"),
2240                      new button(10,h*4,ID_SET_SCROLL_OK,symbol_str("ok_button"),
2241                      new button(40,h*4,ID_WARN_CANCEL,symbol_str("cancel_button"),NULL))),
2242                    symbol_str("WARNING"));
2243        wm->grab_focus(warn_win);
2244      } else wm->Push(new Event(ID_SET_SCROLL_OK,NULL));
2245    } break;
2246    case ID_WARN_CANCEL :
2247    {
2248      wm->close_window(warn_win); warn_win=NULL;
2249      wm->Push(new Event(ID_CANCEL,NULL));
2250    } break;
2251    case ID_SET_SCROLL_OK :
2252    {
2253      if (warn_win) { wm->close_window(warn_win); warn_win=NULL; }
2254      bg_xmul=atoi(mess_win->read(ID_MESS_STR1));
2255      bg_xdiv=atoi(mess_win->read(ID_MESS_STR2));
2256      bg_ymul=atoi(mess_win->read(ID_MESS_STR3));
2257      bg_ydiv=atoi(mess_win->read(ID_MESS_STR4));
2258      wm->Push(new Event(ID_CANCEL,NULL));        // close window
2259    } break;
2260
2261    case ID_CENTER_PLAYER :
2262    {
2263       do_command("center",ev); break;
2264    } break;
2265
2266    case ID_INTERPOLATE_DRAW :
2267    {
2268      interpolate_draw=!interpolate_draw;
2269    } break;
2270
2271    case ID_DISABLE_AUTOLIGHT :
2272    {
2273      disable_autolight=!disable_autolight;
2274    } break;
2275
2276    case ID_ADD_PALETTE :
2277    {
2278      if (!mess_win)
2279      {
2280        int h=wm->font()->height()+8;
2281        mess_win=wm->new_window(xres/2,yres/2,-1,-1,
2282            new text_field(0,h*0,ID_MESS_STR1,symbol_str("ap_width"),"****",2,
2283            new text_field(0,h*1,ID_MESS_STR2,symbol_str("ap_height"),"****",2,
2284            new text_field(0,h*2,ID_MESS_STR3,symbol_str("ap_name"),"***********","pal",
2285                   new button(10,h*3,ID_ADD_PALETTE_OK,symbol_str("ok_button"),
2286                   new button(40,h*3,ID_CANCEL,symbol_str("cancel_button"),NULL))))),symbol_str("ap_pal"));
2287      }
2288    } break;
2289    case ID_ADD_PALETTE_OK :
2290    {
2291      char name[70];
2292      sprintf(name,"(add_palette \"%s\" %d %d)",mess_win->read(ID_MESS_STR3),
2293          atoi(mess_win->read(ID_MESS_STR1)),
2294          atoi(mess_win->read(ID_MESS_STR2)));
2295      char const *s=name;
2296      LObject::Compile(s)->Eval();
2297      wm->Push(new Event(ID_CANCEL,NULL));        // close window
2298    } break;
2299    case ID_TOGGLE_DELAY :
2300    {
2301      the_game->toggle_delay(); break;
2302    } break;
2303
2304    case ID_SMALL_MODE :
2305    {
2306      make_screen_size(311,160); break;
2307    } break;
2308    case ID_CLEAR_WEAPONS :
2309    {
2310      Event ev;
2311      do_command("clear_weapons",ev);
2312    } break;
2313    case ID_GOD_MODE :
2314    {
2315      for (view *v=player_list; v; v=v->next)
2316        v->god=!v->god;
2317    } break;
2318    case ID_MOUSE_SCROLL :
2319    {
2320      mouse_scrolling=!mouse_scrolling;
2321      prop->setd("mouse_scrolling",mouse_scrolling);
2322      if (mouse_scrolling)
2323        the_game->show_help(symbol_str("ms_on"));
2324      else
2325        the_game->show_help(symbol_str("ms_off"));
2326    } break;
2327
2328    case ID_LOCK_PALETTES :
2329    {
2330      palettes_locked=!palettes_locked;
2331      prop->setd("palettes_locked",palettes_locked);
2332      if (palettes_locked)
2333        the_game->show_help(symbol_str("pal_lock"));
2334      else the_game->show_help(symbol_str("pal_unlock"));
2335    } break;
2336
2337    case ID_DISABLE_VIEW_SHIFT :
2338    {
2339      view_shift_disabled=!view_shift_disabled;
2340      prop->setd("view_shift_disabled",view_shift_disabled);
2341      if (view_shift_disabled)
2342        the_game->show_help(symbol_str("vs_dis"));
2343      else the_game->show_help(symbol_str("vs_en"));
2344    } break;
2345
2346    case ID_WIN_FORE :
2347    {
2348      toggle_fgw();
2349    } break;
2350    case ID_WIN_BACK :
2351    {
2352      toggle_bgw();
2353    } break;
2354    case ID_WIN_OBJECTS :
2355    {
2356      toggle_omenu();
2357    } break;
2358    case ID_WIN_PALETTES :
2359    {
2360      toggle_pmenu();
2361    } break;
2362    case ID_WIN_LIGHTING :
2363    {
2364      toggle_light_window();
2365    } break;
2366    case ID_WIN_LAYERS :
2367    {
2368      toggle_show_menu();
2369    } break;
2370    case ID_WIN_CONSOLE :
2371    {
2372      if (dev_console) dev_console->toggle();
2373    } break;
2374    case ID_WIN_TOOLBAR :
2375    {
2376      toggle_toolbar();
2377    } break;
2378
2379    case DEV_AMBIENT :
2380    { if (!ambw) make_ambient(); } break;
2381    case DEV_AREA_OK :
2382    { close_area_win(1); } break;
2383    case DEV_AREA_DELETE :
2384    { close_area_win(0);
2385      if (current_area && current_level)
2386      {
2387        if (current_level->area_list==current_area)
2388          current_level->area_list=current_level->area_list->next;
2389        else
2390        {
2391          area_controller *a=current_level->area_list,*l=NULL;
2392          for (; a!=current_area && a; a=a->next) { l=a; }
2393          l->next=a->next;
2394          delete a;
2395        }
2396        current_area=NULL;
2397        the_game->need_refresh();
2398      }
2399    } break;
2400    case DEV_AI_OK :
2401      close_ai_window(); break;
2402    case DEV_OEDIT_AI :
2403      make_ai_window(edit_object); break;
2404    case DEV_OBJECTS_DELETE :
2405    {
2406      if (edit_object)
2407      {
2408        for (int i=0; i<edit_object->total_objects(); i++)
2409          edit_object->remove_object(edit_object->get_object(0));
2410        the_game->need_refresh();
2411      }
2412    } break;
2413
2414    case DEV_LIGHTS_DELETE :
2415    {
2416      if (edit_object)
2417      {
2418        for (int i=0; i<edit_object->total_lights(); i++)
2419          edit_object->remove_light(edit_object->get_light(0));
2420        the_game->need_refresh();
2421      }
2422    } break;
2423
2424    case DEV_LEDIT_DEL :
2425    {
2426      prop->setd("ledit x",ledit->x);
2427      prop->setd("ledit y",ledit->y);
2428      wm->close_window(ledit); ledit=NULL;
2429      if (current_level)
2430        current_level->remove_light(edit_light);
2431      else
2432        delete_light(edit_light);
2433      edit_light=NULL;
2434      the_game->need_refresh();
2435    } break;
2436    case DEV_LEDIT_OK :
2437    {
2438      edit_light->xshift=atoi(ledit->read(DEV_LEDIT_W));
2439      edit_light->yshift=atoi(ledit->read(DEV_LEDIT_H));
2440      edit_light->inner_radius=atoi(ledit->read(DEV_LEDIT_R1));
2441      edit_light->outer_radius=atoi(ledit->read(DEV_LEDIT_R2));
2442      if (edit_light->outer_radius<=edit_light->inner_radius)
2443      {
2444        edit_light->inner_radius=edit_light->outer_radius-1;
2445        if (edit_light->inner_radius<1)
2446        {
2447          edit_light->inner_radius=1;
2448          edit_light->outer_radius=2;
2449        }
2450      }
2451
2452      edit_light->calc_range();
2453      edit_light=NULL;
2454      prop->setd("ledit x",ledit->x);
2455      prop->setd("ledit y",ledit->y);
2456      wm->close_window(ledit); ledit=NULL;
2457      the_game->need_refresh();
2458    } break;
2459    case DEV_LEDIT_MOVE :
2460    {
2461      prop->setd("ledit x",ledit->x);
2462      prop->setd("ledit y",ledit->y);
2463      wm->close_window(ledit); ledit=NULL;
2464      state=DEV_MOVE_LIGHT;
2465    } break;
2466    case DEV_LEDIT_COPY :
2467    {
2468      edit_light=edit_light->copy();
2469      prop->setd("ledit x",ledit->x);
2470      prop->setd("ledit y",ledit->y);
2471      wm->close_window(ledit); ledit=NULL;
2472      state=DEV_MOVE_LIGHT;
2473    } break;
2474
2475
2476    case DEV_LIGHT0 :
2477    case DEV_LIGHT1 :
2478    case DEV_LIGHT2 :
2479    case DEV_LIGHT3 :
2480    case DEV_LIGHT4 :
2481    case DEV_LIGHT5 :
2482    case DEV_LIGHT6 :
2483    case DEV_LIGHT7 :
2484    case DEV_LIGHT8 :
2485    case DEV_LIGHT9 :
2486    {
2487      vec2i pos = the_game->MouseToGame(vec2i(last_demo_mx, last_demo_my));
2488      edit_light = add_light_source(ev.message.id - DEV_LIGHT0,
2489                                    snap_x(pos.x), snap_y(pos.y),
2490                                    atoi(lightw->read(DEV_LIGHTR1)),
2491                                    atoi(lightw->read(DEV_LIGHTR2)),
2492                                    atoi(lightw->read(DEV_LIGHTW)),
2493                                    atoi(lightw->read(DEV_LIGHTH)));
2494      state=DEV_MOVE_LIGHT;
2495    } break;
2496    case ID_RAISE_ALL :
2497    {
2498      raise_all=!raise_all;
2499      prop->setd("raise_all",raise_all);
2500      if (raise_all)
2501        the_game->show_help(symbol_str("fg_r"));
2502      else
2503        the_game->show_help(symbol_str("fg_l"));
2504    } break;
2505    case DEV_OEDIT_COPY :
2506    {
2507      game_object *use=copy_object;
2508      if (!use) use=edit_object;
2509      if (use)
2510      {
2511        game_object *old=use;
2512        close_oedit_window();
2513        if (use->controller())
2514          the_game->show_help(symbol_str("no_clone"));
2515        else
2516        {
2517          edit_object=old->copy();
2518
2519          current_level->add_object(edit_object);
2520          the_game->need_refresh();
2521          state=DEV_MOVE_OBJECT;
2522
2523          close_oedit_window();
2524          copy_object=NULL;
2525        }
2526      }
2527    } break;
2528    case DEV_OEDIT_LEFT :
2529    {
2530      if (edit_object)
2531      {
2532        the_game->need_refresh();
2533        edit_object->direction=-1;
2534      }
2535    } break;
2536    case DEV_OEDIT_RIGHT :
2537    {
2538      if (edit_object)
2539      {
2540        the_game->need_refresh();
2541        edit_object->direction=1;
2542      }
2543    } break;
2544
2545
2546    case DEV_COMMAND_OK :
2547    {
2548      char cmd[100];
2549      strcpy(cmd,commandw->inm->get(DEV_COMMAND)->read());
2550      prop->setd("commandw x",commandw->x);
2551      prop->setd("commandw y",commandw->y);
2552      wm->close_window(commandw);
2553      commandw=NULL;
2554      do_command(cmd,ev);
2555    } break;
2556
2557    case ID_SHOW_FPS :
2558    { fps_on=!fps_on; } break;
2559    case ID_PROFILE :
2560    { profile_toggle();
2561      profile_on=!profile_on;
2562    } break;
2563
2564    case ID_TOGGLE_NAMES : { show_names=!show_names; } break;
2565    case DEV_QUIT : the_game->end_session(); break;
2566    case DEV_EDIT_FG : dev=1; break; //the_game->draw(); break;
2567    case DEV_EDIT_BG : dev=2; break; //the_game->draw(); break;
2568    case DEV_EDIT_FGBG : dev=3; break; //the_game->draw(); break;
2569    case DEV_PLAY : dev=0; break; //the_game->draw(); break;
2570    case SHOW_FOREGROUND :
2571    { dev=dev^DRAW_FG_LAYER; the_game->need_refresh(); } break;
2572    case SHOW_FOREGROUND_BOUND :
2573    { dev=dev^DRAW_FG_BOUND_LAYER; the_game->need_refresh(); } break;
2574    case SHOW_BACKGROUND :
2575    { dev=dev^DRAW_BG_LAYER; the_game->need_refresh(); } break;
2576    case SHOW_CHARACTERS :
2577    { dev=dev^DRAW_PEOPLE_LAYER; the_game->need_refresh(); } break;
2578    case SHOW_LIGHT :
2579    { dev=dev^DRAW_LIGHTS; the_game->need_refresh(); } break;
2580    case SHOW_LINKS :
2581    { dev=dev^DRAW_LINKS;  the_game->need_refresh(); } break;
2582
2583
2584    case DEV_CREATE :
2585    {
2586      int val=get_omenu_item(((pick_list *)ev.message.data)->get_selection());
2587      char cmd[100];
2588      sprintf(cmd,"create %s",object_names[val]);
2589      do_command(cmd,ev);
2590      state=DEV_CREATE_OBJECT;
2591      dev|=(EDIT_MODE | DRAW_PEOPLE_LAYER);
2592    }
2593    break;
2594
2595    case DEV_PALETTE :
2596    {
2597      int val=((pick_list *)ev.message.data)->get_selection();
2598      pal_wins[val]->open_window();
2599    } break;
2600
2601    case DEV_MUSIC_PICKLIST :
2602    {
2603/*        int *val=((int *)((pick_list *)ev.message.data)->read());
2604        if (current_song) delete current_song;
2605        current_song=new song(song_list[*val]);
2606        current_song->play();        */
2607    }
2608    break;
2609
2610    case DEV_OEDIT_OK :
2611    { close_oedit_window(); } break;
2612
2613    case DEV_OEDIT_DELETE :
2614    {
2615      selected_object=edit_object;
2616      do_command("delete",ev);
2617      close_oedit_window();
2618    }
2619    break;
2620
2621    case DEV_OEDIT_FRONT :
2622    {
2623      do_command("to_front",ev);
2624      close_oedit_window();
2625    }
2626    break;
2627
2628    case DEV_OEDIT_BACK :
2629    {
2630      do_command("to_back",ev);
2631      close_oedit_window();
2632    }
2633    break;
2634
2635    case DEV_OEDIT_MOVE :
2636    {
2637      game_object *o=edit_object;
2638      close_oedit_window();
2639      edit_object=o;
2640      do_command("move",ev);
2641    }
2642    break;
2643      }
2644    } break;
2645
2646
2647    case EV_CLOSE_WINDOW :
2648    {
2649      if (ev.window)
2650      {
2651    if (ev.window==commandw)
2652    {
2653      prop->setd("commandw x",commandw->x);
2654      prop->setd("commandw y",commandw->y);
2655      wm->close_window(commandw);
2656      commandw=NULL;
2657    } else if (ev.window==oedit)
2658      close_oedit_window();
2659    else if (ev.window==ambw)
2660    { wm->close_window(ambw); ambw=NULL; }
2661    else if (ev.window==backw) toggle_bgw();
2662    else if (ev.window==forew) toggle_fgw();
2663    else if (ev.window==lightw) toggle_light_window();
2664    else if (ev.window==show_menu) toggle_show_menu();
2665    else if (ev.window==pmenu) toggle_pmenu();
2666    else if (ev.window==tbw) toggle_toolbar();
2667    else if (ev.window==omenu) toggle_omenu();
2668    else if (ev.window==search_window) toggle_search_window();
2669    else if (profile_handle_event(ev))  profile_on=!profile_on;
2670    else if (chat->chat_event(ev)) chat->toggle();
2671
2672      }
2673    }
2674    break;
2675    case EV_KEYRELEASE :
2676    {
2677      if (ev.key==JK_CTRL_L)
2678      {
2679        if (!edit_object && link_object && selected_object && link_object!=selected_object)
2680    {
2681      link_object->add_object(selected_object);
2682      if (S_LINK_SND>0) cache.sfx(S_LINK_SND)->play(sfx_volume/2);
2683      the_game->need_refresh();
2684    }
2685
2686    link_object=NULL;
2687      }
2688    } break;
2689    case EV_KEY :
2690    {
2691      if (backw && ev.window==backw)
2692      { if (ev.key=='-' && bg_scale<the_game->btile_height()/2)
2693    { toggle_bgw();
2694      bg_scale++;
2695      toggle_bgw();
2696    } else if (ev.key=='+' && bg_scale>1)
2697    { toggle_bgw();
2698      bg_scale--;
2699      toggle_bgw();
2700    } else if (ev.key=='b') toggle_bgw();
2701    else if (ev.key=='B') { toggle_bgw(); bg_w++; if (bg_w>6) bg_w=1; toggle_bgw(); }
2702      }
2703      if (forew && ev.window==forew)
2704      { if (ev.key=='-' && fg_scale<the_game->ftile_height()/2)
2705    { toggle_fgw();
2706      fg_scale++;
2707      toggle_fgw();
2708    } else if (ev.key=='+' && fg_scale>1)
2709    { toggle_fgw();
2710      fg_scale--;
2711      toggle_fgw();
2712    } else if (ev.key=='i')
2713    {
2714      toggle_fgw();
2715      fg_reversed=!fg_reversed;
2716      prop->setd("fg_reversed",fg_reversed);
2717      toggle_fgw();
2718    } else if (ev.key=='f') toggle_fgw();
2719
2720    else if (ev.key=='F') { toggle_fgw(); fg_w++; if (fg_w>6) fg_w=1; toggle_fgw(); }
2721      }
2722      if (ev.window==NULL || ev.window==pmenu ||
2723      ev.window==forew || is_pal_win(ev.window))  // main window actions
2724      {
2725    switch (ev.key)
2726    {
2727      case JK_CTRL_L : if (!edit_object && !link_object) { link_object=selected_object; }
2728      case 'n' : current_level->next_focus(); break;
2729//      case '/' : if (dev_console) dev_console->toggle(); break;
2730      case 't' :
2731      {
2732        if (ev.window==NULL || ev.window==forew)
2733        {
2734          vec2i tile = the_game->GetFgTile(vec2i(last_demo_mx, last_demo_my));
2735          fg_fill(cur_fg, tile.x, tile.y, NULL);
2736        }
2737      } break;
2738      case 'f' : toggle_fgw(); break;
2739      case 'M' : toggle_music_window(); break;
2740
2741      case 'b' : toggle_bgw(); break;
2742      case 'a' : toggle_toolbar(); break;
2743      case 'A' : { if (selected_object)
2744               {
2745             if (oedit) wm->Push(new Event(DEV_OEDIT_OK,NULL));
2746             make_ai_window(selected_object);
2747               }
2748             } break;
2749
2750      case 'o' : toggle_omenu(); break;
2751
2752      case '<' : do_command("to_back",ev); break;
2753
2754      case '>' : do_command("to_front",ev); break;
2755      case 'p' : toggle_pmenu(); break;
2756      case 'P' : profile_toggle(); break;
2757      case '.' :
2758      {
2759        if (last_created_type>=0)
2760        {
2761          int val=last_created_type;
2762          char cmd[100];
2763          sprintf(cmd,"create %s",object_names[val]);
2764          do_command(cmd,ev);
2765          state=DEV_CREATE_OBJECT;
2766          dev|=(EDIT_MODE | DRAW_PEOPLE_LAYER);
2767        }
2768      }
2769      break;
2770
2771
2772      case 'd' : { do_command("delete",ev);  the_game->need_refresh(); } break;
2773      case 'i' :
2774      {
2775        fg_reversed=!fg_reversed;
2776        prop->setd("fg_reversed",fg_reversed);
2777        if (forew)
2778        {
2779          toggle_fgw();
2780          toggle_fgw();
2781        }
2782      } break;
2783      case 'l' : toggle_light_window(); break;
2784      case '!' :
2785      case '@' :
2786      case '#' :
2787      case '$' :
2788      case '%' :
2789      case '^' :
2790      case '&' :
2791      case '*' :
2792      case '(' :
2793      case ')' :
2794
2795      case '0' :
2796      case '1' :
2797      case '2' :
2798      case '3' :
2799      case '4' :
2800      case '5' :
2801      case '6' :
2802      case '7' :
2803      case '8' :
2804      case '9' : do_command("set_aitype",ev); break;
2805      case 'c' : do_command("center",ev); break;
2806      case 'C' :
2807      if (selected_object && selected_object->controller()==NULL)
2808      { copy_object=selected_object;
2809            wm->Push(new Event(DEV_OEDIT_COPY,NULL)); } break;
2810
2811      case 'D' : the_game->toggle_delay(); break;
2812      case 'L' : toggle_show_menu(); break;
2813      case '`' : do_command("fg_select",ev); break;
2814      case 'r' : { do_command("toggle_fg_raise",ev); the_game->need_refresh(); }  break;
2815      case '[' : do_command("fg_add -1",ev); break;
2816      case ']' : do_command("fg_add 1",ev); break;
2817      case 'R' : do_command("reload",ev); break;
2818      case 'w' :
2819      {
2820        vec2i pos = the_game->MouseToGame(vec2i(dlastx, dlasty));
2821        char msg[100]; sprintf(msg, symbol_str("mouse_at"), pos.x, pos.y);
2822        the_game->show_help(msg);
2823        the_game->need_refresh();
2824      } break;
2825      case 'k' :
2826      {
2827        if (selected_object && selected_object->total_objects())
2828          selected_object->remove_object(selected_object->get_object(0));
2829        the_game->need_refresh();
2830      } break;
2831      case 'K' :
2832      {
2833        if (selected_object && selected_object->total_objects())
2834          selected_object->remove_object(selected_object->get_object(selected_object->total_objects()-1));
2835        the_game->need_refresh();
2836      } break;
2837      case 'j' :
2838      {
2839        if (current_level && player_list && player_list->focus)
2840        {
2841          vec2i pos = the_game->MouseToGame(vec2i(dlastx, dlasty));
2842          player_list->focus->x = pos.x;
2843          player_list->focus->y = pos.y;
2844          do_command("center",ev);
2845          the_game->need_refresh();
2846        }
2847      } break;
2848      case 'z' : do_command("clear_weapons",ev); break;
2849      case 'Z' : if (dev&EDIT_MODE)
2850      { view *v = the_game->GetView(vec2i(last_demo_mx, last_demo_my));
2851        if (v)
2852        {
2853          v->god=!v->god;
2854          sbar.redraw(main_screen);
2855        }
2856      } break;
2857      case ' ' :
2858      {
2859        if (dev & EDIT_MODE)
2860        {
2861          if (selected_object)
2862          {
2863        if (oedit)
2864          close_oedit_window();
2865        edit_object=selected_object;
2866        do_command("move",ev);
2867          } else if (selected_light)
2868          {
2869        if (ledit)
2870        {
2871          wm->close_window(ledit);
2872          ledit=NULL;
2873        }
2874        edit_light=selected_light;
2875        do_command("move_light",ev);
2876          }
2877
2878        } break;
2879      }
2880      case 'x' :
2881      {
2882        if (selected_object)
2883        { if (selected_object->direction>0)
2884          selected_object->direction=-1;
2885        else selected_object->direction=1;
2886        }
2887      } break;
2888
2889    }
2890      }
2891    }
2892  }
2893
2894
2895}
2896
2897
2898void dev_controll::add_palette(void *args)
2899{
2900  total_pals++;
2901  pal_wins=(pal_win **)realloc(pal_wins,sizeof(pal_win *)*total_pals);
2902  pal_wins[total_pals-1]=new pal_win(args);
2903}
2904
2905
2906pal_win::pal_win(void *args)
2907{
2908  int i=0;
2909  Cell *ao=(Cell *)args;
2910
2911  name = strdup(lstring_value(CAR(args)));
2912  ao=CDR(ao);
2913  scale=w=h=1;
2914  x=y=0;
2915
2916  if (!NILP(ao))
2917  {
2918    w=lnumber_value(CAR(ao)); ao=CDR(ao);
2919    if (!NILP(ao))
2920    {
2921      h=lnumber_value(CAR(ao)); ao=CDR(ao);
2922      if (!NILP(ao))
2923      {
2924    x=lnumber_value(CAR(ao)); ao=CDR(ao);
2925    if (!NILP(ao))
2926    {
2927      y=lnumber_value(CAR(ao)); ao=CDR(ao);
2928      if (!NILP(ao))
2929        scale=lnumber_value(CAR(ao)); ao=CDR(ao);
2930    }
2931      }
2932    }
2933  }
2934
2935  if (w<=0) w=0;
2936  if (h<=0) h=0;
2937
2938  pat=(unsigned short *)malloc(w*h*sizeof(unsigned short));
2939  memset(pat,0,sizeof(unsigned short)*w*h);   // set the palette to black if no parameters are given
2940  while (!NILP(ao))   // loop until we run out of parameters
2941  {
2942    if (i>w*h)
2943    {
2944      lbreak("to many parameters to add_palette ");
2945      exit(0);
2946    }
2947    pat[i]=lnumber_value(CAR(ao));
2948    // make sure the tile that they suggested exists
2949    if (pat[i]<=0 || pat[i]>nforetiles || foretiles[pat[i]]<0)
2950      pat[i]=0;
2951    ao=CDR(ao);
2952    i++;
2953  }
2954  last_selected=-1;
2955  me=NULL;
2956  open_window();
2957}
2958
2959void pal_win::open_window()
2960{
2961  if (me) close_window();
2962  me=wm->new_window(x,y,w*f_wid/scale,h*f_hi/scale,NULL,name);
2963  draw();
2964}
2965
2966void pal_win::close_window()
2967{
2968  if (me)       // dont' close the window if the window is already closed
2969  {
2970    x=me->x;    //  save the old poisition of the window so that when we  open it
2971                //  it will be in the same spot
2972    y=me->y;
2973    wm->close_window(me);
2974    me=NULL;
2975
2976  }
2977}
2978
2979void pal_win::draw()
2980{
2981  int i,d=cur_fg;
2982  if (me)
2983  {
2984    me->clear();
2985    image *im=new image(vec2i(the_game->ftile_width(),the_game->ftile_height()));
2986    int th=the_game->ftile_height()/scale,tw=the_game->ftile_width()/scale;
2987
2988    for (i=0; i<w*h; i++)
2989    {
2990      im->clear();
2991      the_game->get_fg(pat[i])->im->PutImage(im, vec2i(0,0));
2992      scale_put(im,me->m_surf,me->x1()+(i%w)*tw,
2993        me->y1()+(i/w)*th,tw,th);
2994      if (d==pat[i])
2995      {
2996    me->m_surf->Rectangle(vec2i(me->x1() + (i % w) * tw,
2997                                me->y1() + (i / w) * th),
2998                          vec2i(me->x1() + (i % w) * tw + tw - 1,
2999                                me->y1() + (i / w) * th + th - 1),
3000                          wm->bright_color());
3001      }
3002    }
3003    delete im;
3004    last_selected=d;
3005  }
3006}
3007
3008void pal_win::handle_event(Event &ev)
3009{
3010  int d=cur_fg;
3011
3012  if (d!=last_selected)  // if so see if we need to hilight any of our tiles.
3013  {
3014    int i,dr=0;
3015    for (i=0; i<w*h; i++)
3016    {
3017      if (pat[i]==d || pat[i]==last_selected)
3018        dr=1;
3019    }
3020    if (dr) draw();
3021    last_selected=d;
3022  }
3023
3024  if (ev.window && ev.window==me)
3025  {
3026    switch (ev.type)
3027    {
3028      case EV_MOUSE_BUTTON :
3029      {
3030        if (ev.mouse_button==1)
3031    {
3032      int selx=(last_demo_mx-me->x-me->x1())/(the_game->ftile_width()/scale),
3033          sely=(last_demo_my-me->y-me->y1())/(the_game->ftile_height()/scale);
3034      if (selx>=0 && sely>=0 && selx<w && sely<h)
3035      {
3036        cur_fg=pat[selx+sely*w];
3037        if (dev_cont->forew)
3038          ((tile_picker *)dev_cont->forew->
3039           read(DEV_FG_PICKER))->recenter(dev_cont->forew->m_surf);
3040      }
3041    } else if (ev.mouse_button==2)
3042    {
3043      if (palettes_locked)
3044        the_game->show_help(symbol_str("pal_lock"));
3045      else
3046      {
3047        int selx=(last_demo_mx-me->x-me->x1())/(the_game->ftile_width()/scale),
3048            sely=(last_demo_my-me->y-me->y1())/(the_game->ftile_height()/scale);
3049        if (selx>=0 && sely>=0 && selx<w && sely<h)
3050        {
3051          pat[selx+sely*w]=cur_fg;
3052          draw();
3053        }
3054      }
3055    }
3056      } break;
3057
3058      case EV_KEY :
3059      {
3060        switch (ev.key)
3061    {
3062      case '+' :
3063      { if (scale>1)
3064        {
3065          close_window();
3066          scale--;
3067          open_window();
3068        }
3069      } break;
3070      case '-' :
3071      { if (scale<the_game->ftile_height()/2)
3072        {
3073          close_window();
3074          scale++;
3075          open_window();
3076        }
3077      } break;
3078      case JK_LEFT :
3079      {
3080        if (palettes_locked) the_game->show_help(symbol_str("pal_lock"));
3081        else if (w>1) resize(-1,0);
3082      } break;
3083      case JK_RIGHT :
3084      {
3085        if (palettes_locked) the_game->show_help(symbol_str("pal_lock"));
3086        else
3087          resize(1,0);
3088      } break;
3089      case JK_UP :
3090      {
3091        if (palettes_locked) the_game->show_help(symbol_str("pal_lock"));
3092        else if (h>1) resize(0,-1);
3093      } break;
3094      case JK_DOWN :
3095      {
3096        if (palettes_locked)
3097          the_game->show_help(symbol_str("pal_lock"));
3098        else
3099          resize(0,1);
3100      } break;
3101      case JK_ESC : close_window();     break;
3102      case ' ' :
3103      {
3104        int32_t xx, yy;
3105        vec2i tile = the_game->GetFgTile(vec2i(me->x, me->y));
3106
3107        for (xx=tile.x; xx<tile.x+w; xx++)
3108        {
3109          for (yy=tile.y; yy<tile.y+h; yy++)
3110          {
3111        if (xx>=0 && yy>=0 && xx<current_level->foreground_width() &&
3112            yy<current_level->foreground_height())
3113          the_game->put_fg(xx,yy,raise_all ? make_above_tile(pat[xx-tile.x+(yy-tile.y)*w]) : pat[xx-tile.x+(yy-tile.y)*w] );
3114          }
3115        }
3116      } break;
3117      case 't' :
3118      {
3119        vec2i tile = the_game->GetFgTile(vec2i(me->x, me->y));
3120        dev_cont->fg_fill(-1, tile.x, tile.y, this);
3121      } break;
3122
3123    }
3124      } break;
3125
3126      case EV_CLOSE_WINDOW : close_window(); break;
3127    }
3128  }
3129
3130
3131}
3132
3133
3134void pal_win::resize(int xa, int ya)
3135{
3136  int i,j;
3137  unsigned short *npat;
3138  if (w+xa<1 || y+ya<1) return ;
3139
3140  npat=(unsigned short *)malloc(sizeof(unsigned short)*(w+xa)*(h+ya));
3141  memset(npat,0,sizeof(unsigned short)*(w+xa)*(h+ya));
3142  for (i=0; i<(w+xa); i++)
3143    for (j=0; j<(h+ya); j++)
3144      if (i+j*w<w*h)
3145        npat[i+j*(w+xa)]=pat[i+j*w];
3146  free(pat);
3147  w+=xa;
3148  h+=ya;
3149  pat=npat;
3150  last_selected=-1;
3151  close_window();
3152  open_window();
3153}
3154
3155
3156void pal_win::save(FILE *fp)
3157{
3158  if (me)
3159  {
3160    x=me->x;
3161    y=me->y;
3162  }
3163
3164  fprintf(fp,"(add_palette \"%s\" %ld %ld %ld %ld %ld ",name,(long)w,(long)h,(long)x,(long)y,(long)scale);
3165  int i;
3166  for (i=0; i<w*h; i++)
3167    fprintf(fp,"%d ",pat[i]&0x7fff);
3168  fprintf(fp,")\n");
3169
3170}
3171
3172void dev_controll::save()
3173{
3174  FILE *fp=open_FILE("edit.lsp","w");
3175  if (!fp)
3176    the_game->show_help(symbol_str("no_edit.lsp"));
3177  else
3178  {
3179    fprintf(fp,"(set_zoom %d)\n",the_game->zoom);
3180
3181    int i;
3182    for (i=0; i<total_pals; i++)
3183    {
3184      pal_wins[i]->save(fp);
3185    }
3186    fprintf(fp,"\n");
3187    fclose(fp);
3188  }
3189
3190}
3191
3192int dev_controll::is_pal_win(Jwindow *win)
3193{
3194  int i;
3195  for (i=0; i<total_pals; i++)
3196    if (win==pal_wins[i]->me) return 1;
3197  return 0;
3198}
3199
3200
3201class fill_rec
3202{
3203public :
3204  short x,y;
3205  fill_rec *last;
3206  fill_rec(short X, short Y, fill_rec *Last)
3207  { x=X; y=Y; last=Last; }
3208} ;
3209
3210static int get_color(int color, int x, int y, pal_win *p)
3211{
3212  if (p)
3213  {
3214    while (x<0) x+=p->width();
3215    while (y<0) y+=p->height();
3216    return p->get_pat(x%p->width(),y%p->height());
3217  }
3218  else return color;
3219}
3220
3221void dev_controll::fg_fill(int color, int x, int y, pal_win *p)
3222{
3223  unsigned short *sl,*above,*below;
3224  fill_rec *recs=NULL,*r;
3225  unsigned short fcolor;
3226  sl=current_level->get_fgline(y);
3227  fcolor=fgvalue(sl[x]);
3228  int startx=x,starty=y;
3229  if (fcolor==color) return ;
3230  do
3231  {
3232    if (recs)
3233    { r=recs;
3234      recs=recs->last;
3235      x=r->x; y=r->y;
3236      delete r;
3237    }
3238    sl=current_level->get_fgline(y);
3239    if (fgvalue(sl[x])==fcolor)
3240    {
3241      while (x>0 && fgvalue(sl[x])==fcolor) x--;
3242      if (fgvalue(sl[x])!=fgvalue(fcolor) && x<current_level->foreground_width()-1) x++;
3243      if (y>0)
3244      {
3245        above=current_level->get_fgline(y-1);
3246        if (fgvalue(above[x])==fcolor)
3247        { r=new fill_rec(x,y-1,recs);
3248          recs=r;
3249        }
3250      }
3251      if (y<current_level->foreground_height()-1)
3252      {
3253        above=current_level->get_fgline(y+1);
3254        if (above[x]==fcolor)
3255        { r=new fill_rec(x,y+1,recs);
3256          recs=r;
3257        }
3258      }
3259
3260
3261
3262      do
3263      {
3264        sl[x]=get_color(color,x-startx,y-starty,p);
3265        if (y>0)
3266        { above=current_level->get_fgline(y-1);
3267          if (x>0 && fgvalue(above[x-1])!=fgvalue(fcolor) && fgvalue(above[x])==fgvalue(fcolor))
3268          { r=new fill_rec(x,y-1,recs);
3269            recs=r;
3270          }
3271        }
3272        if (y<current_level->foreground_height()-1)
3273        { below=current_level->get_fgline(y+1);
3274          if (x>0 && fgvalue(below[x-1])!=fgvalue(fcolor) && fgvalue(below[x])==fgvalue(fcolor))
3275          { r=new fill_rec(x,y+1,recs);
3276            recs=r;
3277          }
3278        }
3279        x++;
3280      } while (fgvalue(sl[x])==fgvalue(fcolor) && x<current_level->foreground_width());
3281      x--;
3282      if (y>0)
3283      {
3284        above=current_level->get_fgline(y-1);
3285        if (fgvalue(above[x])==fgvalue(fcolor))
3286        { r=new fill_rec(x,y-1,recs);
3287          recs=r;
3288        }
3289      }
3290      if (y<current_level->foreground_height()-1)
3291      {
3292        above=current_level->get_fgline(y+1);
3293        if (fgvalue(above[x])==fgvalue(fcolor))
3294        { r=new fill_rec(x,y+1,recs);
3295          recs=r;
3296        }
3297      }
3298    }
3299  } while (recs);
3300  the_game->need_refresh();
3301}
3302
3303static int get_char_mem(int type, int print)
3304{
3305  int t=0;
3306  for (int j=0; j<MAX_STATE; j++)
3307  {
3308    if (figures[type]->has_sequence((character_state)j))
3309    {
3310      int s=figures[type]->get_sequence((character_state)j)->MemUsage();
3311      if (print)
3312        dprintf("(%s=%d)",state_names[j],s);
3313      t+=s;
3314    }
3315  }
3316  if (print)
3317    dprintf("\ntotal=%d\n",t);
3318  return t;
3319}
3320
3321void dev_controll::show_char_mem(char const *name)
3322{
3323  int find=-1;
3324  for (int i=0; i<total_objects; i++)
3325  {
3326    if (!strcmp(name,object_names[i]))
3327      find=i;
3328  }
3329  if (find<0)
3330    dprintf("No character '%s' defined\n",name);
3331  else
3332    get_char_mem(find,1);
3333
3334}
3335
3336void dev_controll::show_mem()
3337{
3338  int t=0,s=0;
3339  int i=0;
3340  for (; i<nforetiles; i++)
3341  {
3342    if (foretiles[i]>=0)
3343    {
3344      if (cache.loaded(foretiles[i]))
3345      {
3346    t++;
3347    s+=cache.foret(foretiles[i])->size();
3348      }
3349    }
3350  }
3351  dprintf("%d loaded foretiles=%d bytes\n",t,s);
3352
3353  t=0; s=0;
3354  for (i=0; i<nbacktiles; i++)
3355  {
3356    if (backtiles[i]>=0)
3357    {
3358      if (cache.loaded(foretiles[i]))
3359      {
3360    t++;
3361    s+=cache.backt(backtiles[i])->size();
3362      }
3363    }
3364  }
3365  dprintf("%d loaded backtiles=%d bytes\n",t,s);
3366
3367  t=0; s=0;
3368  for (i=0; i<total_objects; i++)
3369  {
3370    t++;
3371    s+=get_char_mem(i,0);
3372  }
3373  dprintf("%d character=%d bytes\n",t,s);
3374
3375}
3376
3377
3378
3379void dev_cleanup()
3380{
3381  if (start_edit)
3382    prop->save("defaults.prp");
3383  delete prop;
3384  if (listable_objs)
3385  {
3386    free(listable_objs);
3387    listable_objs=NULL;
3388  }
3389  crc_manager.clean_up();
3390
3391}
3392
3393
3394
3395struct pmi
3396{
3397  char const *name;
3398  int id;
3399  char const *on_off;
3400  int key;
3401} ;
3402
3403
3404static pmi filemenu[]={
3405          { "menu1_load",         ID_LEVEL_LOAD,NULL,-1},
3406      { NULL,0,NULL,-1},
3407      { "menu1_save",     ID_LEVEL_SAVE,NULL,-1},
3408      { "menu1_saveas",      ID_LEVEL_SAVEAS,NULL,-1},
3409      { "menu1_savegame",          ID_GAME_SAVE,NULL,-1},
3410      { "menu1_new",          ID_LEVEL_NEW,NULL,-1},
3411      { "menu1_resize",         ID_LEVEL_RESIZE,NULL,-1},
3412      { NULL,0,NULL,-1},
3413      { "menu1_suspend",ID_SUSPEND,NULL,-1},
3414      { "menu1_toggle",ID_PLAY_MODE,NULL,-1},
3415      { NULL,0,NULL,-1},
3416      { "menu1_savepal",ID_EDIT_SAVE,NULL,-1},
3417//      { "menu1_startc",ID_CACHE_PROFILE,NULL,-1},
3418//      { "menu1_endc",ID_CACHE_PROFILE_END,NULL,-1},
3419      { NULL,0,NULL,-1},
3420      { "menu1_quit",      ID_QUIT,NULL,-1},
3421      { NULL,-1,NULL,-1}
3422    };
3423
3424
3425static pmi editmenu[]={
3426  { "menu2_light",               ID_TOGGLE_LIGHT,NULL,-1},
3427  { "menu2_scroll",            ID_SET_SCROLL,NULL,-1},
3428  { "menu2_center",       ID_CENTER_PLAYER,NULL,-1},
3429  { "menu2_addpal",                ID_ADD_PALETTE,NULL,-1},
3430  { "menu2_delay",          ID_TOGGLE_DELAY,NULL,-1},
3431
3432  { "menu2_god",                   ID_GOD_MODE,NULL,-1},
3433  { "menu2_clear",          ID_CLEAR_WEAPONS,NULL,-1},
3434  { "menu2_mscroll",               ID_MOUSE_SCROLL,&mouse_scrolling,-1},
3435  { "menu2_lock",       ID_LOCK_PALETTES,&palettes_locked,-1},
3436  { "menu2_raise",       ID_RAISE_ALL,&raise_all,-1},
3437  { "menu2_names",        ID_TOGGLE_NAMES,&show_names,-1},
3438
3439  { NULL,0,NULL,-1},
3440  { "menu2_map",      ID_TOGGLE_MAP,NULL,-1},
3441//  { "Shrink to 320x200 (F10)",    ID_SMALL_MODE,NULL,-1},
3442  { "menu2_view",        ID_DISABLE_VIEW_SHIFT,&view_shift_disabled,-1},
3443//  { "Ultra Smooth draw (U)",      ID_INTERPOLATE_DRAW,  &interpolate_draw,'U'},
3444  { "menu2_alight",      ID_DISABLE_AUTOLIGHT, &disable_autolight,'A'},
3445  { "menu2_fps",         ID_SHOW_FPS,          &fps_on,-1},
3446//  { NULL,0,NULL,-1},
3447//  { "Record demo",                ID_RECORD_DEMO,NULL,-1},
3448//  { "Play demo",                  ID_PLAY_DEMO,NULL,-1},
3449  { NULL,-1,NULL,-1}
3450};
3451
3452
3453
3454// Window Menus
3455static pmi winmenu[]={
3456          { "menu3_fore",    ID_WIN_FORE,    &forew_on,-1},
3457          { "menu3_back",    ID_WIN_BACK,    &backw_on,-1},
3458          { "menu3_layers",    ID_WIN_LAYERS,  &show_menu_on,-1},
3459      { "menu3_light",    ID_WIN_LIGHTING,&ledit_on,-1},
3460      { "menu3_pal",    ID_WIN_PALETTES,&pmenu_on,-1},
3461      { "menu3_objs",    ID_WIN_OBJECTS, &omenu_on,-1},
3462//      { "menu3_console",    ID_WIN_CONSOLE, &commandw_on,-1},
3463      { "menu3_toolbar",    ID_WIN_TOOLBAR, &tbw_on,-1},
3464//      { "Search      (s)",    ID_SEARCH,      &searchw_on,-1},
3465      { "menu3_prof",    ID_PROFILE,     &profile_on,-1},
3466      { "menu3_save",     ID_SAVE_WINDOWS,NULL,-1},
3467      { NULL,-1,NULL,-1}
3468    };
3469
3470
3471
3472/*
3473static pmi filemenu[]={
3474          { "Load Level",         ID_LEVEL_LOAD,NULL,-1},
3475      { NULL,0,NULL,-1},
3476      { "Save Level (S)",     ID_LEVEL_SAVE,NULL,-1},
3477      { "Save level as",      ID_LEVEL_SAVEAS,NULL,-1},
3478      { "Save game",          ID_GAME_SAVE,NULL,-1},
3479      { "New level",          ID_LEVEL_NEW,NULL,-1},
3480      { "Resize map",         ID_LEVEL_RESIZE,NULL,-1},
3481      { NULL,0,NULL,-1},
3482      { "Suspend non-players",ID_SUSPEND,NULL,-1},
3483      { "Play mode toggle (TAB)",ID_PLAY_MODE,NULL,-1},
3484      { NULL,0,NULL,-1},
3485      { "Save Palettes         ",ID_EDIT_SAVE,NULL,-1},
3486      { "Start cache profile   ",ID_CACHE_PROFILE,NULL,-1},
3487      { "End cache profile     ",ID_CACHE_PROFILE_END,NULL,-1},
3488      { NULL,0,NULL,-1},
3489      { "Quit      (Q)",      ID_QUIT,NULL,-1},
3490      { NULL,-1,NULL,-1}
3491    };
3492
3493
3494static pmi editmenu[]={
3495  { "Toggle light",               ID_TOGGLE_LIGHT,NULL,-1},
3496  { "Set scroll rate",            ID_SET_SCROLL,NULL,-1},
3497  { "Center on player   (c)",       ID_CENTER_PLAYER,NULL,-1},
3498  { "Add palette",                ID_ADD_PALETTE,NULL,-1},
3499  { "Toggle Delays      (D)",          ID_TOGGLE_DELAY,NULL,-1},
3500
3501  { "God mode",                   ID_GOD_MODE,NULL,-1},
3502  { "Clear weapons (z)",          ID_CLEAR_WEAPONS,NULL,-1},
3503  { "Mouse scroll",               ID_MOUSE_SCROLL,&mouse_scrolling,-1},
3504  { "Lock palette windows",       ID_LOCK_PALETTES,&palettes_locked,-1},
3505  { "Raise all foreground",       ID_RAISE_ALL,&raise_all,-1},
3506  { "Toggle object names",        ID_TOGGLE_NAMES,&show_names,-1},
3507
3508  { NULL,0,NULL,-1},
3509  { "Toggle map        (m)",      ID_TOGGLE_MAP,NULL,-1},
3510//  { "Shrink to 320x200 (F10)",    ID_SMALL_MODE,NULL,-1},
3511  { "Disable view shifts",        ID_DISABLE_VIEW_SHIFT,&view_shift_disabled,-1},
3512//  { "Ultra Smooth draw (U)",      ID_INTERPOLATE_DRAW,  &interpolate_draw,'U'},
3513  { "Disable Autolight (A)",      ID_DISABLE_AUTOLIGHT, &disable_autolight,'A'},
3514  { "Show FPS/Obj count",         ID_SHOW_FPS,          &fps_on,-1},
3515//  { NULL,0,NULL,-1},
3516//  { "Record demo",                ID_RECORD_DEMO,NULL,-1},
3517//  { "Play demo",                  ID_PLAY_DEMO,NULL,-1},
3518  { NULL,-1,NULL,-1}
3519};
3520
3521
3522
3523// Window Menus
3524static pmi winmenu[]={
3525          { "Foreground  (f)",    ID_WIN_FORE,    &forew_on,-1},
3526          { "Background  (b)",    ID_WIN_BACK,    &backw_on,-1},
3527          { "Draw layers (L)",    ID_WIN_LAYERS,  &show_menu_on,-1},
3528      { "Lighting    (l)",    ID_WIN_LIGHTING,&ledit_on,-1},
3529      { "Palettes    (p)",    ID_WIN_PALETTES,&pmenu_on,-1},
3530      { "Objects     (o)",    ID_WIN_OBJECTS, &omenu_on,-1},
3531      { "Console     (/)",    ID_WIN_CONSOLE, &commandw_on,-1},
3532      { "Tool Bar    (a)",    ID_WIN_TOOLBAR, &tbw_on,-1},
3533//      { "Search      (s)",    ID_SEARCH,      &searchw_on,-1},
3534      { "Profile     (P)",    ID_PROFILE,     &profile_on,-1},
3535      { "Save positions",     ID_SAVE_WINDOWS,NULL,-1},
3536      { NULL,-1,NULL,-1}
3537    };
3538
3539*/
3540
3541static pmenu_item *i_recurse(pmi *first)
3542{
3543  if (first->id==-1)
3544    return NULL;
3545  else
3546    return new pmenu_item(first->id,first->name ? symbol_str(first->name) : 0,first->on_off,first->key,i_recurse(first+1));
3547}
3548
3549static pmenu *make_menu(int x, int y)
3550{
3551  return new pmenu(x,y,
3552         new pmenu_item(symbol_str("file_top"),new psub_menu(i_recurse(filemenu),NULL),
3553     new pmenu_item(symbol_str("edit_top"),new psub_menu(i_recurse(editmenu),NULL),
3554     new pmenu_item(symbol_str("window_top"),new psub_menu(i_recurse(winmenu),NULL),NULL))),main_screen);
3555}
3556
3557
3558
3559void toggle_edit_mode()
3560{
3561  dev=dev^EDIT_MODE;
3562  if (dev&EDIT_MODE)
3563  {
3564    wm->SetMouseShape(cache.img(c_normal)->copy(), vec2i(1, 1));
3565    pal->load();
3566  }
3567  else
3568  {
3569    if (dev&MAP_MODE) dev-=MAP_MODE;                        // no map mode while playing!
3570    wm->SetMouseShape(cache.img(c_target)->copy(), vec2i(8, 8));
3571  }
3572  if ((dev&EDIT_MODE) && !dev_menu)
3573  {
3574    dev_menu=make_menu(0,yres-wm->font()->height()-5);
3575  }
3576  else if (!(dev&EDIT_MODE) && dev_menu)
3577  {
3578    delete dev_menu;
3579    dev_menu=NULL;
3580  }
3581}
3582
3583
3584int dev_controll::ok_to_scroll()
3585{
3586  if (state==DEV_MOVE_LIGHT || state==DEV_MOVE_OBJECT || mouse_scrolling) return 1;
3587  else return 0;
3588}
3589
3590dev_controll::~dev_controll()
3591{
3592  for (int i=0; i<total_pals; i++)
3593    delete pal_wins[i];
3594  if (total_pals)
3595    free(pal_wins);
3596}
3597
3598
3599
3600pal_win::~pal_win()
3601{
3602  free(pat);
3603  free(name);
3604}
Note: See TracBrowser for help on using the repository browser.