#include "config.h"

/*  Copyright (C) 2002  Brad Jorsch <anomie@users.sourceforge.net>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <stdio.h>
#include <stdlib.h>
#if TM_IN_SYS_TIME
# if TIME_WITH_SYS_TIME
#  include <sys/time.h>
#  include <time.h>
# else
#  if HAVE_SYS_TIME_H
#   include <sys/time.h>
#  else
#   include <time.h>
#  endif
# endif
#else
#include <time.h>
#endif
#include <ctype.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <errno.h>

#include <X11/Xlib.h>
#include <X11/xpm.h>

#include "wmgeneral/wmgeneral-x11.h"
#include "wmgeneral/mouse_regions.h"
#include "wmgeneral/xpm_trans.h"

#include "wmweather_master.xpm"
static int wmweather_mask_width;
static int wmweather_mask_height;
static char *wmweather_mask_bits;

#include "wmweather+.h"
#include "convert.h"
#include "metar.h"
#include "avn.h"
#include "eta.h"
#include "mrf.h"
#include "warnings.h"
#include "forecast.h"
#include "radar.h"
#include "animation.h"
#include "die.h"
#include "font.h"

/* Globals */
int current_mode;
struct forecast *cur_forecast;
int window_X, window_Y;

#define X 4
#define P 4
#define M (((100/P)+1)*X)
static struct forecast *last_fcst;
static int last_font=-1;
static time_t last_time=0;
static int but_stat=-1;
static int dclick=0;
static int dclick_counter=-1;
static time_t update_time;
static int forecast_priority, last_priority;
static struct animation anim;
static int counter_timer=0;
static int show_counter;
static int min_pct;
static int sigs=0;


/* Prototypes */

void DrawDisplay(int force);


/* Functions */

void sigusr2(int i){
    sigs |= 2;
    if(signal(SIGUSR2, sigusr2)==SIG_ERR)
        warn("Error setting SIGUSR2 signal handler!");
}

void sigusr1(int i){
    sigs |= 1;
    if(signal(SIGUSR1, sigusr1)==SIG_ERR)
        warn("Error setting SIGUSR1 signal handler!");
}

void sigfunc(int i){
    sigs |= i<<8;
    if(signal(i, sigfunc)==SIG_ERR)
        warn("Error setting %d signal handler!", i);
}

void do_cleanup(void){
    metar_cleanup();
    warnings_cleanup();
    avn_cleanup();
    eta_cleanup();
    mrf_cleanup();
    radar_cleanup();
}

void init_dock(int argc, char **argv){
    sscanf(wmweather_master_xpm[0], "%d %d %*s", &wmweather_mask_width, &wmweather_mask_height);
    wmweather_mask_bits=malloc((wmweather_mask_width+7)/8*wmweather_mask_height);
    if(!wmweather_mask_bits) die("malloc failed");
    createXBMfromXPM(wmweather_mask_bits, wmweather_master_xpm, wmweather_mask_width, wmweather_mask_height);
    openDockWindow(argc, argv, wmweather_master_xpm, wmweather_mask_bits, wmweather_mask_width, wmweather_mask_height);

    AddMouseRegion(0, 5, 5, 23, 14);   /* Cur button */
    AddMouseRegion(1, 23, 5, 41, 14);  /* Fcst burron */
    AddMouseRegion(2, 41, 5, 59, 14);  /* Map button */
    AddMouseRegion(3, 5, 17, 59, 59); /* Large window */
    AddMouseRegion(4, 5, 17, 11, 24);   /* left forecast arrow */
    AddMouseRegion(5, 53, 17, 59, 24);  /* right forecast arrow */
    AddMouseRegion(6, 14, 17, 50, 24); /* forecast little window */
    AddMouseRegion(7, 5, 27, 59, 59); /* forecast big window */

    init_metar();
    if(warning_zones) init_warnings();
    if(avn_station) init_avn();
    if(eta_station) init_eta();
    if(mrf_station) init_mrf();
    init_radar();
    errno=0;
    if(atexit(do_cleanup)) warn("atexit() failed, files will not be cleaned up\n");

    current_mode=starting_mode;
    window_X=0; window_Y=0;
    cur_forecast=NULL;
    last_fcst=NULL;
    last_font=-1;
    last_time=0;
    anim.do_animate=start_do_animation;
    anim.show_counter=0;
    anim.changed=1;
    anim.min_pct=1;
    anim.old_pct=0;
    min_pct=20;
    show_counter=0;
    but_stat=-1;
    dclick=0;
    dclick_counter=-1;
    update_time=0;
    forecast_priority=4;
    last_priority=-1;

    if(signal(SIGUSR1, sigusr1)==SIG_ERR)
        warn("Error setting SIGUSR1 signal handler!");
    if(signal(SIGUSR2, sigusr2)==SIG_ERR)
        warn("Error setting SIGUSR2 signal handler!");
    if(signal(SIGHUP, sigfunc)==SIG_ERR)
        warn("Error setting SIGHUP signal handler!");
    if(signal(SIGINT, sigfunc)==SIG_ERR)
        warn("Error setting SIGINT signal handler!");
    if(signal(SIGPIPE, sigfunc)==SIG_ERR)
        warn("Error setting SIGPIPE signal handler!");
    if(signal(SIGTERM, sigfunc)==SIG_ERR)
        warn("Error setting SIGTERM signal handler!");

    DrawDisplay(1);
}


void update_dock(){
    XEvent Event;
    int i=0, j;
    int exposeflag=0;

    j=sigs;
    sigs=0;
    if(j){
        if(j&~3) exit(j);
        if(j&1) i=current_mode;
        if(j&2) i=-1;
        if(j&3){
            switch(i){
              case 0:
                update_metar(1);
                break;
              case 1:
                update_avn(1);
                update_eta(1);
                update_mrf(1);
                break;
              case 2:
                update_radar(1);
                break;
              default:
                update_metar(1);
                update_avn(1);
                update_eta(1);
                update_mrf(1);
                update_radar(1);
                break;
            }
        }
    }

    if(update_time<time(NULL)){
        update_time=time(NULL)+2;
        update_metar(0);
        update_avn(0);
        update_eta(0);
        update_mrf(0);
        update_radar(0);
        forecast_priority=(forecast_priority+1)%5;
        DrawDisplay(0);
    }
    if(counter_timer>0) if(!--counter_timer){
        anim.changed=1;
        show_counter=anim.show_counter=0;
    }

    if(dclick_counter>-1) dclick_counter--;

    while(XPending(display)){
        XNextEvent(display, &Event);
        switch (Event.type){
          case GraphicsExpose:
          case NoExpose:
          case Expose:
            exposeflag=1;
            break;
          case DestroyNotify:
            XCloseDisplay(display);
            exit(0);
            break;
          case ButtonPress:
            but_stat = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
            if((dclick!=but_stat+1 && dclick!=-but_stat-1) || dclick_counter<0){
                dclick=-but_stat-1;
                dclick_counter=4;
            } else if(dclick==-but_stat-1) dclick=but_stat+1;

            switch(but_stat){
              case 0:
              case 1:
              case 2:
                if(current_mode!=but_stat){
                    current_mode=but_stat;
                    if(!anim.do_animate && !show_counter){
                        show_counter=1;
                        counter_timer=10;
                    }
                    DrawDisplay(1);
                }
                break;
              case 3:
              case 7:
                switch(Event.xbutton.button){
                  case 2:
                    if(current_mode==2){
                        if(radar_cross!=NULL){
                            do_radar_cross=1;
                            DrawDisplay(1);
                        }
                    } else {
                        anim.changed=1;
                        anim.show_counter=0;
                        anim.do_animate=!anim.do_animate;
                        anim.min_pct=1;
                        if(!anim.do_animate && current_mode==1){
                            anim.min_pct=min_pct;
                            show_counter=anim.show_counter=1;
                            counter_timer=20;
                        }
                    }
                    break;

                  case 4:
                    if(current_mode==1 && !anim.do_animate && min_pct<100){
                        if(Event.xbutton.state&ShiftMask){
                            min_pct+=10;
                            if(min_pct>100) min_pct=100;
                        } else min_pct++;
                        anim.min_pct=min_pct;
                        show_counter=anim.show_counter=1;
                        counter_timer=20;
                        anim.changed=1;
                    }
                    break;

                  case 5:
                    if(current_mode==1 && !anim.do_animate && min_pct>0){
                        if(Event.xbutton.state&ShiftMask){
                            min_pct-=10;
                            if(min_pct<0) min_pct=0;
                        } else min_pct--;
                        anim.min_pct=min_pct;
                        anim.show_counter=1;
                        counter_timer=20;
                        anim.changed=1;
                    }
                    break;

                  case 6:
                    if(current_mode==1){
                        show_counter=anim.show_counter=1;
                        anim.changed=1;
                        counter_timer=0;
                    }
                    break;
                }
                break;

              case 4:
                copyPixmapArea(123, 96, 6, 7, 65, 17);
                break;
              case 5:
                copyPixmapArea(129, 96, 6, 7, 113, 17);
                break;
            }
            break;

          case ButtonRelease:
            i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
            if(dclick_counter<0) dclick=0;

            if(but_stat==4){
                copyPixmapArea(123, 89, 6, 7, 65, 17);
            }
            if(but_stat==5){
                copyPixmapArea(129, 89, 6, 7, 113, 17);
            }
            if(current_mode==2 && (but_stat==3 || but_stat==7)
               && Event.xbutton.button==2){
                do_radar_cross=0;
                DrawDisplay(1);
            }

            if(but_stat == i && but_stat >= 0){
                switch(but_stat){
                  case 3:
                  case 7:
                    if(Event.xbutton.button==1){
                        if(dclick==but_stat+1) kill(getpid(), SIGUSR1);
                        else if(warning_zones) output_warnings(0);
                    }
                    if(Event.xbutton.button==2){
                        if(dclick==but_stat+1 && current_mode==1){
                            show_counter=anim.show_counter=!anim.show_counter;
                            anim.changed=1;
                            counter_timer=0;
                        }
                    }
                    if(Event.xbutton.button==3 && warning_zones) output_warnings(1);
                    if(Event.xbutton.button==6){
                        show_counter=anim.show_counter=0;
                        anim.changed=1;
                    }
                    break;
                  case 4:
                    current_forecast_next(-1);
                    forecast_priority=4;
                    last_priority=0;
                    DrawDisplay(0);
                    break;
                  case 5:
                    current_forecast_next(1);
                    forecast_priority=4;
                    last_priority=0;
                    DrawDisplay(0);
                    break;
                  case 6:
                    if(Event.xbutton.button==3) current_forecast_next(-1);
                    if(Event.xbutton.button==2){{
                        struct forecast *f=current_forecast_get();
                        struct forecast *g;
                        current_forecast_next(1);
                        while((g=current_forecast_get())!=f){
                            if((f->hour<0 && g->hour>=0) ||
                               (f->hour>=0 && g->hour<0)) break;
                            current_forecast_next(1);
                        }
                    }}
                    if(Event.xbutton.button==1) current_forecast_next(1);
                    forecast_priority=4;
                    last_priority=0;
                    DrawDisplay(0);
                    break;
                }
                but_stat=-1;
            }
            break;
        }
    }
    if(exposeflag){
        setMaskXY(-window_X, -window_Y);
        RedrawWindowXY(window_X, window_Y);
    }
    DoAnimation(&anim);
}


void DrawDisplay(int force){
    int font=0;
    int x, y, z;
    struct forecast *f;
    time_t t;
    struct tm *tm;

    if(current_warnings) font=1;
    if(force || last_font!=font) last_time=-1;
    last_font=font;

    switch(current_mode){
      case 0:
        if(last_time==current.last_update) break;
        last_time=current.last_update;
        EnableMouseRegion(3);
        DisableMouseRegion(4);
        DisableMouseRegion(5);
        DisableMouseRegion(6);
        DisableMouseRegion(7);
        window_X=0; window_Y=0;

        copyPixmapArea(124, 0, 54, 9, 5, 5);
        copyPixmapArea(124, 9, 18, 9, 5, 5);
        copyPixmapArea(124, 18, 54, 42, 5, 17);

        DrawString(7, 17, metar_station, font+1);
        if(current.month>0 && current.month<13 && current.date!=-1){
            snprintf(bigbuf, BIGBUF_LEN, "%s %d", monthnames[(int)current.month], current.date);
            DrawString(32, 17, bigbuf, font+1);
        }
        if(current.time!=-1){
            snprintf(bigbuf, BIGBUF_LEN, "%04dL  (%04dZ)", current.time, local2utc(current.time, NULL, NULL, NULL, NULL));
            DrawString(7, 23, bigbuf, font+1);
        }
        if(current.temp!=999){
            x=(temp_mode==0)?temp_C2F(current.temp):current.temp;
            if(x<-99) x=-99;
            if(x>199) x=199;
            snprintf(bigbuf, BIGBUF_LEN, "%d", x);
            DrawString(32, 29, bigbuf, font);
        }
        if(current.rh!=-1){
            DrawChar(55, 29, '%', font);
            DrawNumber(54, 29, current.rh, font);
        }
        if(current.windspeed==0){
            x=GetStringWidth("CALM");
            DrawString(32+(26-x)/2, 35, "CALM", font);
        } else {
            if(current.winddir>=0 && current.winddir<=16){
                x=GetStringWidth(directions[current.winddir]);
                DrawString(45-x, 35, directions[current.winddir], font);
            }
            switch(windspeed_mode){
              case 0:
                x=knots2mph(current.windspeed);
                break;
              case 1:
                x=knots2kph(current.windspeed);
                break;
              case 3:
                x=knots2mps(current.windspeed);
                break;
              case 4:
                x=knots2beaufort(current.windspeed);
                break;
            }
            if(x>=0 && x<1000)
                DrawNumber(58, 35, x, font);
        }
        if(current.pressure>0){
            switch(pressure_mode){
              case 1:
                snprintf(bigbuf, BIGBUF_LEN, "P:%4.0f", inHg2hPa(current.pressure));
                break;
              case 2:
                snprintf(bigbuf, BIGBUF_LEN, "P:%5.1f", inHg2mmHg(current.pressure));
                break;
              case 3:
                snprintf(bigbuf, BIGBUF_LEN, "P:%5.3f", inHg2atm(current.pressure));
                break;
              default:
                snprintf(bigbuf, BIGBUF_LEN, "P:%5.2f", current.pressure);
                break;
            }
            DrawString(32, 41, bigbuf, font);
        }
        if(current.heatindex!=999){
            x=(temp_mode==0)?current.heatindex:temp_F2C(current.heatindex);
            if(x<-99) x=-99;
            if(x>199) x=199;
            snprintf(bigbuf, BIGBUF_LEN, "HI: %d", x);
            DrawString(32, 47, bigbuf, font);
        }
        if(current.windchill!=999){
            x=(temp_mode==0)?current.windchill:temp_F2C(current.windchill);
            if(x<-99) x=-99;
            if(x>199) x=199;
            snprintf(bigbuf, BIGBUF_LEN, "WC: %d", x);
            DrawString(32, 53, bigbuf, font);
        }

        anim.show_counter=0;
        anim.min_pct=1;
        SetAnimation(&anim, 5, 28, current.sky, current.obs, current.vis,
                     current.frz, current.snow, current.rain, current.tstorm, 0,
                     current.moon);

        break;

      case 1:
        f=current_forecast_get();
        if(last_fcst!=f) last_time=-1;
        last_fcst=f;
        if(f!=NULL){
            if(last_time==f->last_update)
                goto case_1_end; /* still check bottom line priority */
            else last_time=f->last_update;
        }

        DisableMouseRegion(3);
        EnableMouseRegion(4);
        EnableMouseRegion(5);
        EnableMouseRegion(6);
        EnableMouseRegion(7);
        window_X=60; window_Y=0;
        last_priority=-1;

        copyPixmapArea(124, 0, 54, 9, 65, 5);
        copyPixmapArea(142, 9, 18, 9, 83, 5);
        copyPixmapArea(123, 89, 6, 7, 65, 17);
        copyPixmapArea(129, 89, 6, 7, 113, 17);
        copyPixmapArea(124, 18, 36, 7, 74, 17);
        copyPixmapArea(124, 18, 54, 32, 65, 27);

        if(f==NULL) break;

        t=time(NULL);
        tm=localtime(&t);
        bigbuf[0]='\0';
        if(tm->tm_mon+1==f->month && tm->tm_mday==f->day){
            if(f->hour<0) snprintf(bigbuf, BIGBUF_LEN, "TODAY");
            else snprintf(bigbuf, BIGBUF_LEN, "TODAY   %dL", f->hour);
        } else {
            x=tm->tm_mon+1;
            y=tm->tm_mday+1;
            fix_date(&x, &y, NULL, NULL);
            if(x==f->month && y==f->day){
                if(f->hour<0) snprintf(bigbuf, BIGBUF_LEN, "TOMORROW");
                else snprintf(bigbuf, BIGBUF_LEN, "TMRW   %dL", f->hour);
            } else {
                z=0;
                if(f->wday!=-1){
                    for(z=0; z<5; z++){
                        y++;
                        fix_date(&x, &y, NULL, NULL);
                        if(x==f->month && y==f->day){
                            if(f->hour<0) snprintf(bigbuf, BIGBUF_LEN, "%s",
                                                   wdaynames[(int)f->wday]);
                            else snprintf(bigbuf, BIGBUF_LEN, "%.3s   %dL",
                                          wdaynames[(int)f->wday], f->hour);
                            z=99;
                        }
                    }
                }
                if(z<99 && f->month>0 && f->day>0){
                    if(f->hour<0)
                        snprintf(bigbuf, BIGBUF_LEN, "%.3s   %d",
                                 monthnames[(int)f->month], f->day);
                    else snprintf(bigbuf, BIGBUF_LEN, "%.3s %d %dL",
                                  monthnames[(int)f->month], f->day,
                                  f->hour);
                }
            }
        }
        x=GetStringWidth(bigbuf);
        DrawString(60+(64-x)/2, 18, bigbuf, font);

        x=GetStringWidth(f->station);
        DrawString(118-x, 28, f->station, font+1);

        if(f->high!=999 || f->low!=999){
            DrawChar(104, 35, '/', font);
            if(f->high!=999){
                x=(temp_mode==0)?f->high:temp_F2C(f->high);
                if(x<-99) x=-99;
                if(x>199) x=199;
                DrawNumber(103, 35, x, font);
            }
            if(f->low!=999){
                x=(temp_mode==0)?f->low:temp_F2C(f->low);
                if(x<-99) x=-99;
                if(x>199) x=199;
                DrawNumber(118, 35, x, font);
            }
        }
        if(f->temp!=999){
            x=(temp_mode==0)?f->temp:temp_F2C(f->temp);
            if(x<-99) x=-99;
            if(x>199) x=199;
            snprintf(bigbuf, BIGBUF_LEN, "%d", x);
            DrawString(92, 41, bigbuf, font);
        }
        if(f->rh!=-1){
            DrawChar(115, 41, '%', font);
            DrawNumber(114, 41, f->rh, font);
        }
        if(f->windspeed==0){
            x=GetStringWidth("CALM");
            DrawString(92+(26-x)/2, 47, "CALM", font);
        } else {
            if(f->winddir>=0 && f->winddir<=16){
                x=GetStringWidth(directions[f->winddir]);
                DrawString(105-x, 47, directions[f->winddir], font);
            }
            switch(windspeed_mode){
              case 0:
                x=knots2mph(f->windspeed);
                break;
              case 1:
                x=knots2kph(f->windspeed);
                break;
              case 3:
                x=knots2mps(f->windspeed);
                break;
              case 4:
                x=knots2beaufort(f->windspeed);
                break;
            }
            if(x>=0 && x<1000)
                DrawNumber(118, 47, x, font);
        }

        anim.show_counter=show_counter;
        anim.min_pct=min_pct;
        SetAnimation(&anim, 65, 28, f->sky, f->obs, f->vis,
                     f->frz, f->snow, f->rain, f->tstorm, f->svtstorm,
                     f->moon);

case_1_end:
        if(f==NULL || forecast_priority==last_priority) break;

        /* This is a little tricky. We use the switch as a calculated goto
         * (ick) to determine which order to try things in. Fall-through is
         * intended. */
        switch(forecast_priority){
          default:
            /* WTF? Oh well, just start at the beginning */

          case 0:
            if(f->heatindex>=80 && f->heatindex!=999){
                copyPixmapArea(124, 18, 26, 5, 92, 53);
                x=(temp_mode==0)?f->heatindex:temp_F2C(f->heatindex);
                snprintf(bigbuf, BIGBUF_LEN, "HI: %d", x);
                DrawString(92, 53, bigbuf, font);
                forecast_priority=0;
                break;
            }

          case 1:
            if(f->windchill<=40 && f->windchill!=999){
                copyPixmapArea(124, 18, 26, 5, 92, 53);
                x=(temp_mode==0)?f->windchill:temp_F2C(f->windchill);
                snprintf(bigbuf, BIGBUF_LEN, "WC: %d", x);
                DrawString(92, 53, bigbuf, font);
                forecast_priority=1;
                break;
            }

          case 2:
            if(f->snowamt>0){
                copyPixmapArea(124, 18, 26, 5, 92, 53);
                if(f->snowamt==1){ x=1; y=2; }
                else if(f->snowamt==8){ x=8; y=-1; }
                else { x=f->snowamt; y=x+2; }
                if(length_mode==1){
                    x=in2cm(x); y=in2cm(y);
                }
                if(x>9 && y>9) x=9;
                if(y==-1) snprintf(bigbuf, BIGBUF_LEN, "SN:>%d", x);
                else snprintf(bigbuf, BIGBUF_LEN, "SN:%d-%d", x, y);
                DrawString(92, 53, bigbuf, font);
                forecast_priority=2;
                break;
            }

          case 3:
            if(f->precipamt>0){
                copyPixmapArea(124, 18, 26, 5, 92, 53);
                switch(f->precipamt){
                  case 1:
                    if(length_mode==0) DrawString(92, 53, "P:.01-.1", font);
                    if(length_mode==1) DrawString(92, 53, "P: 0-.25", font);
                    break;
                  case 2:
                    if(length_mode==0) DrawString(92, 53, "P:.1-.25", font);
                    if(length_mode==1) DrawString(92, 53, "P:.25-.6", font);
                    break;
                  case 3:
                    if(length_mode==0) DrawString(92, 53, "P:.25-.5", font);
                    if(length_mode==1) DrawString(92, 53, "P:.6-1.3", font);
                    break;
                  case 4:
                    if(length_mode==0) DrawString(92, 53, "P: .5-1", font);
                    if(length_mode==1) DrawString(92, 53, "P: 1-2.5", font);
                    break;
                  case 5:
                    if(length_mode==0) DrawString(92, 53, "P: 1-2", font);
                    if(length_mode==1) DrawString(92, 53, "P: 2.5-5", font);
                    break;
                  case 6:
                    if(length_mode==0) DrawString(92, 53, "P: >2", font);
                    if(length_mode==1) DrawString(92, 53, "P: >5", font);
                    break;
                  case 7:
                    if(length_mode==0) DrawString(92, 53, "P: >3", font);
                    if(length_mode==1) DrawString(92, 53, "P: >7.6", font);
                    break;
                }
                forecast_priority=3;
                break;
            }

          case 4:
            copyPixmapArea(124, 18, 26, 5, 92, 53);
            x=GetStringWidth("<")+1;
            y=GetStringWidth(f->ID)+1;
            z=GetStringWidth(">");
            DrawChar(118-x-y-z, 53, '<', font+1);
            DrawString(118-y-z, 53, f->ID, font+1);
            DrawChar(118-z, 53, '>', font+1);
            forecast_priority=4;
            break;
        }
        last_priority=forecast_priority;
        break;

      case 2:
        if(last_time==radar_update_time) break;
        last_time=radar_update_time;
        EnableMouseRegion(3);
        DisableMouseRegion(4);
        DisableMouseRegion(5);
        DisableMouseRegion(6);
        DisableMouseRegion(7);
        window_X=0; window_Y=0;

        copyPixmapArea(124, 0, 54, 9, 5, 5);
        copyPixmapArea(160, 9, 18, 9, 41, 5);
        put_radar(6, 18, font);

        anim.active=0;
        break;
    }
    DoAnimation(&anim);
}