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

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

build: SDL2 compilation fixes.

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