/* track.c - Created by Giampiero Caprino This file is part of Train Director Train Director 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, or (at your option) any later version. Train Director 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 Train Director; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #if !defined(__unix__) #include #endif #include "trsim.h" #include "ask.h" #define OLD /* old way of drawing tracks */ int terse_status; extern int current_tool; grcolor fieldcolors[MAXFIELDCOL]; int link_startx, link_starty; int current_macro = -1; int auto_link = 1; char *current_macro_name; Track **macros; int nmacros, maxmacros; VLines n_s_layout[] = { { HGRID / 2 + 1, 0, HGRID / 2 + 1, VGRID - 1 }, { HGRID / 2 - 0, 0, HGRID / 2 - 0, VGRID - 1 }, { -1 } }; SegDir n_s_segs[] = { SEG_N, SEG_S, SEG_END }; SegDir sw_n_segs[] = { SEG_SW, SEG_N, SEG_END }; SegDir nw_s_segs[] = { SEG_NW, SEG_S, SEG_END }; SegDir w_e_segs[] = { SEG_W, SEG_E, SEG_END }; SegDir nw_e_segs[] = { SEG_NW, SEG_E, SEG_END }; SegDir sw_e_segs[] = { SEG_SW, SEG_E, SEG_END }; SegDir w_ne_segs[] = { SEG_W, SEG_NE, SEG_END }; SegDir w_se_segs[] = { SEG_W, SEG_SE, SEG_END }; SegDir nw_se_segs[] = { SEG_NW, SEG_SE, SEG_END }; SegDir sw_ne_segs[] = { SEG_SW, SEG_NE, SEG_END }; SegDir ne_s_segs[] = { SEG_NE, SEG_S, SEG_END }; SegDir se_n_segs[] = { SEG_SE, SEG_N, SEG_END }; VLines sw_n_layout[] = { { HGRID / 2 + 1, 0, HGRID / 2 + 1, VGRID / 2 }, { HGRID / 2 - 0, 0, HGRID / 2 - 0, VGRID / 2 }, { HGRID / 2 + 1, VGRID / 2, 1, VGRID - 1 }, { HGRID / 2 - 0, VGRID / 2, 0, VGRID - 1 }, { HGRID / 2 - 0, VGRID / 2 - 1, 0, VGRID - 2 }, { -1 } }; VLines nw_s_layout[] = { { 1, 0, HGRID / 2 + 1, VGRID / 2 }, { 0, 0, HGRID / 2 - 0, VGRID / 2 }, { 0, 1, HGRID / 2 - 1, VGRID / 2 }, { HGRID / 2 + 1, VGRID / 2 - 0, HGRID / 2 + 1, VGRID - 1 }, { HGRID / 2 - 0, VGRID / 2 - 0, HGRID / 2 - 0, VGRID - 1 }, { -1 } }; VLines se_n_layout[] = { { HGRID / 2 + 1, 0, HGRID / 2 + 1, VGRID / 2 }, { HGRID / 2 - 0, 0, HGRID / 2 - 0, VGRID / 2 }, { HGRID / 2 + 1, VGRID / 2, HGRID - 1, VGRID - 2 }, { HGRID / 2 - 0, VGRID / 2, HGRID - 1, VGRID - 1 }, { HGRID / 2 - 0, VGRID / 2 + 1, HGRID - 2, VGRID - 1 }, { -1 } }; VLines ne_s_layout[] = { { HGRID / 2, VGRID / 2 - 1, HGRID - 2, 0 }, { HGRID / 2, VGRID / 2, HGRID - 1, 0 }, { HGRID / 2 + 1, VGRID / 2, HGRID - 1, 1 }, { HGRID / 2 + 1, VGRID / 2 - 0, HGRID / 2 + 1, VGRID - 1 }, { HGRID / 2 - 0, VGRID / 2 - 0, HGRID / 2 - 0, VGRID - 1 }, { -1 } }; VLines w_e_layout[] = { /*{ 0, VGRID / 2 - 1, HGRID - 1, VGRID / 2 - 1 },*/ { 0, VGRID / 2 - 0, HGRID - 1, VGRID / 2 - 0 }, { 0, VGRID / 2 + 1, HGRID - 1, VGRID / 2 + 1 }, { -1 } }; VLines nw_e_layout[] = { { 1, 0, HGRID / 2, VGRID / 2 - 1 }, { 0, 0, HGRID / 2, VGRID / 2 - 0 }, { 0, 1, HGRID / 2, VGRID / 2 + 1 }, /*{ HGRID / 2, VGRID / 2 - 1, HGRID - 1, VGRID / 2 - 1 },*/ { HGRID / 2, VGRID / 2 - 0, HGRID - 1, VGRID / 2 - 0 }, { HGRID / 2, VGRID / 2 + 1, HGRID - 1, VGRID / 2 + 1 }, { -1 } }; VLines sw_e_layout[] = { { 0, VGRID - 2, HGRID / 2 - 1, VGRID / 2 /*- 1*/ }, { 0, VGRID - 1, HGRID / 2, VGRID / 2 - 0 }, { 1, VGRID - 1, HGRID / 2, VGRID / 2 + 1 }, /*{ HGRID / 2, VGRID / 2 - 1, HGRID - 1, VGRID / 2 - 1 },*/ { HGRID / 2, VGRID / 2 - 0, HGRID - 1, VGRID / 2 - 0 }, { HGRID / 2, VGRID / 2 + 1, HGRID - 1, VGRID / 2 + 1 }, { -1 } }; VLines w_ne_layout[] = { /*{ 0, VGRID / 2 - 1, HGRID / 2, VGRID / 2 - 1 },*/ { 0, VGRID / 2 - 0, HGRID / 2, VGRID / 2 - 0 }, { 0, VGRID / 2 + 1, HGRID / 2, VGRID / 2 + 1 }, { HGRID / 2, VGRID / 2 - 1, HGRID - 2, 0 }, { HGRID / 2, VGRID / 2 - 0, HGRID - 1, 0 }, { HGRID / 2, VGRID / 2 + 1, HGRID - 1, 1 }, { -1 } }; VLines w_se_layout[] = { /*{ 0, VGRID / 2 - 1, HGRID / 2 - 0, VGRID / 2 - 1 },*/ { 0, VGRID / 2 - 0, HGRID / 2, VGRID / 2 - 0 }, { 0, VGRID / 2 + 1, HGRID / 2, VGRID / 2 + 1 }, { HGRID / 2 + 1, VGRID / 2 /*- 1*/, HGRID - 1, VGRID - 2 }, { HGRID / 2, VGRID / 2 - 0, HGRID - 1, VGRID - 1 }, { HGRID / 2, VGRID / 2 + 1, HGRID - 2, VGRID - 1 }, { -1 } }; VLines sweng_sw_ne_straight[] = { { 0, VGRID - 2, HGRID - 2, 0 }, { 0, VGRID - 1, HGRID - 1, 0 }, { 1, VGRID - 1, HGRID - 1, 1 }, { 0, VGRID / 2, HGRID / 2 - 1, VGRID / 2 }, { 0, VGRID / 2 + 1, HGRID / 2 - 1, VGRID / 2 + 1 }, { HGRID / 2 + 1, VGRID / 2 + 1, HGRID - 1, VGRID / 2 + 1 }, { HGRID / 2 + 1, VGRID / 2 - 0, HGRID - 1, VGRID / 2 - 0 }, { -1 } }; VLines sweng_sw_ne_switched[] = { { 0, VGRID / 2, HGRID - 2, 0 }, { 0, VGRID / 2 + 1, HGRID - 1, 0 }, { 0, VGRID - 1, HGRID - 1, VGRID / 2 }, { 1, VGRID - 1, HGRID - 1, VGRID / 2 + 1 }, { -1 } }; VLines sweng_nw_se_straight[] = { { 1, 0, HGRID - 1, VGRID - 2 }, { 0, 0, HGRID - 1, VGRID - 1 }, { 0, 1, HGRID - 2, VGRID - 1 }, { 0, VGRID / 2, HGRID / 2 - 1, VGRID / 2 }, { 0, VGRID / 2 + 1, HGRID / 2 - 1, VGRID / 2 + 1 }, { HGRID / 2 + 1, VGRID / 2 + 1, HGRID - 1, VGRID / 2 + 1 }, { HGRID / 2 + 1, VGRID / 2 - 0, HGRID - 1, VGRID / 2 - 0 }, { -1 } }; VLines sweng_nw_se_switched[] = { { 0, 0, HGRID - 1, VGRID / 2 }, { 0, 1, HGRID - 1, VGRID / 2 + 1 }, { 0, VGRID / 2, HGRID - 1, VGRID - 2 }, { 1, VGRID / 2 + 1, HGRID - 1, VGRID - 1 }, { -1 } }; VLines block_layout[] = { { HGRID / 2, VGRID / 2 - 1, HGRID / 2, VGRID / 2 + 2 }, { -1 } }; VLines block_layout_ns[] = { { HGRID / 2 - 1, VGRID / 2, HGRID / 2 + 2, VGRID / 2 }, { -1 } }; VLines nw_se_layout[] = { { 1, 0, HGRID - 1, VGRID - 2 }, { 0, 0, HGRID - 1, VGRID - 1 }, { 0, 1, HGRID - 2, VGRID - 1 }, { -1 } }; VLines sw_ne_layout[] = { { 0, VGRID - 2, HGRID - 2, 0 }, { 0, VGRID - 1, HGRID - 1, 0 }, { 1, VGRID - 1, HGRID - 1, 1 }, { -1 } }; VLines switch_rect[] = { { 0, 0, HGRID - 1, 0 }, { HGRID - 1, 0, HGRID - 1, VGRID - 1 }, { 0, 0, 0, VGRID - 1 }, { 0, VGRID - 1, HGRID - 1, VGRID - 1 }, { -1 } }; VLines w_e_platform_out[] = { { 0, VGRID / 2 - 3, HGRID - 1, VGRID / 2 - 3 }, { 0, VGRID / 2 + 3, HGRID - 1, VGRID / 2 + 3 }, { 0, VGRID / 2 - 3, 0, VGRID / 2 + 3 }, { HGRID - 1, VGRID / 2 - 3, HGRID - 1, VGRID / 2 + 3 }, { -1 } }; VLines w_e_platform_in[] = { { 1, VGRID / 2 - 2, HGRID - 2, VGRID / 2 - 2 }, { 1, VGRID / 2 - 1, HGRID - 2, VGRID / 2 - 1 }, { 1, VGRID / 2 - 0, HGRID - 2, VGRID / 2 - 0 }, { 1, VGRID / 2 + 1, HGRID - 2, VGRID / 2 + 1 }, { 1, VGRID / 2 + 2, HGRID - 2, VGRID / 2 + 2 }, { -1 } }; VLines n_s_platform_out[] = { { HGRID / 2 - 3, 0, HGRID / 2 - 3, VGRID - 1 }, { HGRID / 2 + 3, 0, HGRID / 2 + 3, VGRID - 1 }, { HGRID / 2 - 3, 0, HGRID / 2 + 3, 0 }, { HGRID / 2 - 3, VGRID - 1, HGRID / 2 + 3, VGRID - 1 }, { -1 } }; VLines n_s_platform_in[] = { { HGRID / 2 - 2, 1, HGRID / 2 - 2, VGRID - 2 }, { HGRID / 2 - 1, 1, HGRID / 2 - 1, VGRID - 2 }, { HGRID / 2 - 0, 1, HGRID / 2 - 0, VGRID - 2 }, { HGRID / 2 + 1, 1, HGRID / 2 + 1, VGRID - 2 }, { HGRID / 2 + 2, 1, HGRID / 2 + 2, VGRID - 2 }, { -1 } }; #if 0 VLines w_link[] = { { 0, VGRID / 2, HGRID / 2, VGRID / 2 }, { HGRID / 2, VGRID / 2, HGRID / 2 + 4, VGRID / 2 - 4 }, { HGRID / 2, VGRID / 2, HGRID / 2 + 4, VGRID / 2 + 4 }, { -1 } }; VLines e_link[] = { { HGRID / 2 - 4, VGRID / 2 - 4, HGRID / 2, VGRID / 2 }, { HGRID / 2 - 4, VGRID / 2 + 4, HGRID / 2, VGRID / 2 }, { HGRID / 2, VGRID / 2, HGRID - 1, VGRID / 2 }, { -1 } }; #endif void *e_train_pmap_default[4]; void *w_train_pmap_default[4]; void *e_train_pmap[4]; static const char * e_train_xpm[] = { "13 10 3 1", " c #FFFFFFFFFFFF", ". c #000000000000", NULL, /*"X c #0000FFFFFFFF",*/ " ", "........... ", ".XXXXXXXXX.. ", ".X..X..X..X..", ".XXXXXXXXXXX.", ".XXXXXXXXXXX.", ".............", " ... ... ", " ", " "}; void *w_train_pmap[4]; static const char * w_train_xpm[] = { "13 10 3 1", " c #FFFFFFFFFFFF", ". c #000000000000", NULL, /*"X c #0000FFFFFFFF",*/ " ", " ...........", " ..XXXXXXXXX.", "..X.X..X..XX.", ".XXXXXXXXXXX.", ".XXXXXXXXXXX.", ".............", " ... ... ", " ", " "}; static void *speed_pmap; static const char *speed_xpm[] = { "8 3 3 1", " c #FFFFFFFFFFFF", ". c #000000000000", "X c #000000000000", " .... ", " .. .. ", " .... "}; static void *camera_pmap; static const char *camera_xpm[] = { "13 10 3 1", " c #FFFFFFFFFFFF", ". c #000000000000", "X c #0000FFFFFFFF", " ", " .. ", " ........... ", " . .. . ", " . ... . ", " . . . . ", " . ... . ", " . . ", " ........... ", " "}; static void *e_sig_pmap[2]; /* R, G */ static const char *e_sig_xpm[] = { "9 7 3 1", " c #FFFFFFFFFFFF", ". c #000000000000", NULL, /*"X c #0000FFFFFFFF",*/ " ", " ", ". ... ", ". .GGG.", ".....GGG.", ". .GGG.", ". ... "}; static void *w_sig_pmap[2]; /* R, G */ static const char *w_sig_xpm[] = { "9 7 3 1", " c #FFFFFFFFFFFF", ". c #000000000000", NULL, /*"X c #0000FFFFFFFF",*/ " ", " ", " ... .", ".GGG. .", ".GGG.....", ".GGG. .", " ... ." }; static void *e_sig2_pmap[4]; /* RR, GR, GG, GO */ static const char *e_sig2_xpm[] = { "13 7 4 1", " c #FFFFFFFFFFFF", ". c #000000000000", NULL, /*"G c #0000FFFFFFFF",*/ NULL, /*"X c #0000FFFFFFFF",*/ " ", " ", ". ... ... ", ". .XXX..GGG.", "....XXX..GGG.", ". .XXX..GGG.", ". ... ... "}; static void *e_sigP_pmap[4]; /* RR, GR, GG, GO */ static const char *e_sigP_xpm[] = { "13 7 4 1", " c #FFFFFFFFFFFF", ". c #000000000000", NULL, /*"G c #0000FFFFFFFF",*/ NULL, /*"X c #0000FFFFFFFF",*/ " ", " ", ". ...... ... ", ". XXXXX..GGG.", "....X.X..GGG.", ". ..XXX..GGG.", ". ...... ... "}; static void *w_sig2_pmap[4]; /* RR, GR, GG, GO */ static const char *w_sig2_xpm[] = { "13 7 4 1", " c #FFFFFFFFFFFF", ". c #000000000000", NULL, /*"G c #0000FFFFFFFF",*/ NULL, /*"X c #0000FFFFFFFF",*/ " ", " ", " ... ... .", ".GGG..XXX. .", ".GGG..XXX....", ".GGG..XXX. .", " ... ... ."}; static void *w_sigP_pmap[4]; /* RR, GR, GG, GO */ static const char *w_sigP_xpm[] = { "13 7 4 1", " c #FFFFFFFFFFFF", ". c #000000000000", NULL, /*"G c #0000FFFFFFFF",*/ NULL, /*"X c #0000FFFFFFFF",*/ " ", " ", " ... ...... .", ".GGG..XXX.. .", ".GGG..X.X....", ".GGG..XXXXX .", " ... ...... ."}; static char buff[256]; void init_pmaps(void) { int r, g, b; int fgr, fgg, fgb; char bufffg[64]; getcolor_rgb(fieldcolors[COL_TRACK], &fgr, &fgg, &fgb); sprintf(bufffg, ". c #%02x00%02x00%02x00", fgr, fgg, fgb); getcolor_rgb(fieldcolors[COL_BACKGROUND], &r, &g, &b); sprintf(buff, " c #%02x00%02x00%02x00", r, g, b); sprintf(buff, " c lightgray", r, g, b); e_train_xpm[1] = w_train_xpm[1] = buff; e_train_xpm[2] = w_train_xpm[2] = bufffg; e_train_xpm[3] = w_train_xpm[3] = "X c orange"; e_train_pmap[0] = get_pixmap(e_train_xpm); w_train_pmap[0] = get_pixmap(w_train_xpm); e_train_xpm[3] = w_train_xpm[3] = "X c cyan"; e_train_pmap[1] = get_pixmap(e_train_xpm); w_train_pmap[1] = get_pixmap(w_train_xpm); e_train_xpm[3] = w_train_xpm[3] = "X c blue"; e_train_pmap[2] = get_pixmap(e_train_xpm); w_train_pmap[2] = get_pixmap(w_train_xpm); e_train_xpm[3] = w_train_xpm[3] = "X c yellow"; e_train_pmap[3] = get_pixmap(e_train_xpm); w_train_pmap[3] = get_pixmap(w_train_xpm); sprintf(bufffg, ". c #%02x00%02x00%02x00", fgr, fgg, fgb); sprintf(buff, " c #%02x00%02x00%02x00", r, g, b); sprintf(buff, " c lightgray", r, g, b); e_sig_xpm[1] = w_sig_xpm[1] = buff; e_sig_xpm[2] = w_sig_xpm[2] = bufffg; e_sig_xpm[3] = w_sig_xpm[3] = "G c red"; e_sig_pmap[0] = get_pixmap(e_sig_xpm); w_sig_pmap[0] = get_pixmap(w_sig_xpm); e_sig_xpm[3] = w_sig_xpm[3] = "G c green"; e_sig_pmap[1] = get_pixmap(e_sig_xpm); w_sig_pmap[1] = get_pixmap(w_sig_xpm); e_sig2_xpm[1] = w_sig2_xpm[1] = e_sigP_xpm[1] = w_sigP_xpm[1] = buff; e_sig2_xpm[2] = w_sig2_xpm[2] = e_sigP_xpm[2] = w_sigP_xpm[2] = bufffg; e_sig2_xpm[3] = w_sig2_xpm[3] = e_sigP_xpm[3] = w_sigP_xpm[3] = "G c red"; e_sig2_xpm[4] = w_sig2_xpm[4] = "X c red"; e_sigP_xpm[4] = w_sigP_xpm[4] = "X c gray"; e_sig2_pmap[0] = get_pixmap(e_sig2_xpm); w_sig2_pmap[0] = get_pixmap(w_sig2_xpm); e_sigP_pmap[0] = get_pixmap(e_sigP_xpm); w_sigP_pmap[0] = get_pixmap(w_sigP_xpm); e_sig2_xpm[3] = w_sig2_xpm[3] = "G c green"; e_sigP_xpm[3] = w_sigP_xpm[3] = "G c green"; e_sig2_xpm[4] = w_sig2_xpm[4] = "X c red"; e_sigP_xpm[4] = w_sigP_xpm[4] = "X c gray"; e_sig2_pmap[1] = get_pixmap(e_sig2_xpm); w_sig2_pmap[1] = get_pixmap(w_sig2_xpm); e_sigP_pmap[1] = get_pixmap(e_sigP_xpm); w_sigP_pmap[1] = get_pixmap(w_sigP_xpm); e_sig2_xpm[3] = w_sig2_xpm[3] = "G c green"; e_sig2_xpm[4] = w_sig2_xpm[4] = "X c green"; e_sigP_xpm[4] = w_sigP_xpm[4] = "X c white"; e_sig2_pmap[2] = get_pixmap(e_sig2_xpm); w_sig2_pmap[2] = get_pixmap(w_sig2_xpm); e_sigP_pmap[2] = get_pixmap(e_sigP_xpm); w_sigP_pmap[2] = get_pixmap(w_sigP_xpm); e_sig2_xpm[3] = w_sig2_xpm[3] = "G c red"; e_sigP_xpm[3] = w_sigP_xpm[3] = "G c red"; e_sig2_xpm[4] = w_sig2_xpm[4] = "X c orange"; e_sigP_xpm[4] = w_sigP_xpm[4] = "X c white"; e_sig2_pmap[3] = get_pixmap(e_sig2_xpm); w_sig2_pmap[3] = get_pixmap(w_sig2_xpm); e_sigP_pmap[3] = get_pixmap(e_sigP_xpm); w_sigP_pmap[3] = get_pixmap(w_sigP_xpm); sprintf(buff, " c #%02x00%02x00%02x00", r, g, b); sprintf(bufffg, ". c #%02x00%02x00%02x00", fgr, fgg, fgb); speed_xpm[1] = buff; speed_xpm[2] = bufffg; speed_pmap = get_pixmap(speed_xpm); for(r = 0; r < 4; ++r) { e_train_pmap_default[r] = e_train_pmap[r]; w_train_pmap_default[r] = w_train_pmap[r]; } } Track *track_new(void) { Track *t; t = malloc(sizeof(Track)); memset(t, 0, sizeof(Track)); t->xsize = 1; t->ysize = 1; t->type = NOTRACK; t->direction = NODIR; t->fgcolor = fieldcolors[COL_TRACK]; return(t); } void track_delete(Track *t) { Track *t1, *old; if(t == layout) layout = t->next; else { old = layout; for(t1 = old->next; t1 != t; t1 = t1->next) old = t1; old->next = t->next; } if(t->station) free(t->station); free(t); } void track_name(Track *t, char *name) { if(t->station) free(t->station); t->station = strdup(name); } void track_draw(Track *t) { int fg; VLines *lns; fg = t->fgcolor; switch(t->status) { case ST_FREE: break; case ST_BUSY: fg = color_red; break; case ST_READY: fg = color_green; break; case ST_WORK: fg = color_blue; } switch(t->direction) { case TRK_N_S: #ifndef OLD draw_segments(t->x, t->y, n_s_segs, fg); goto n; #else lns = n_s_layout; break; #endif case SW_N: #ifndef OLD draw_segments(t->x, t->y, sw_n_segs, fg); goto n; #else lns = sw_n_layout; break; #endif case NW_S: #ifndef OLD draw_segments(t->x, t->y, nw_s_segs, fg); goto n; #else lns = nw_s_layout; break; #endif case W_E: #ifndef OLD draw_segments(t->x, t->y, w_e_segs, fg); goto n; #else lns = w_e_layout; break; #endif case NW_E: #ifndef OLD draw_segments(t->x, t->y, nw_e_segs, fg); goto n; #else lns = nw_e_layout; break; #endif case SW_E: #ifndef OLD draw_segments(t->x, t->y, sw_e_segs, fg); goto n; #else lns = sw_e_layout; break; #endif case W_NE: #ifndef OLD draw_segments(t->x, t->y, w_ne_segs, fg); goto n; #else lns = w_ne_layout; break; #endif case W_SE: #ifndef OLD draw_segments(t->x, t->y, w_se_segs, fg); goto n; #else lns = w_se_layout; break; #endif case NW_SE: #ifndef OLD draw_segments(t->x, t->y, nw_se_segs, fg); goto n; #else lns = nw_se_layout; break; #endif case SW_NE: #ifndef OLD draw_segments(t->x, t->y, sw_ne_segs, fg); goto n; #else lns = sw_ne_layout; break; #endif case NE_S: #ifndef OLD draw_segments(t->x, t->y, ne_s_segs, fg); goto n; #else lns = ne_s_layout; break; #endif case SE_N: #ifndef OLD draw_segments(t->x, t->y, se_n_segs, fg); goto n; #else lns = se_n_layout; break; #endif } draw_layout(t->x, t->y, lns, fg); n: if(show_blocks && t->direction == W_E && t->length >= 100) draw_layout(t->x, t->y, block_layout, fieldcolors[TRACK]); if(show_blocks && t->direction == TRK_N_S && t->length >= 100) draw_layout(t->x, t->y, block_layout_ns, fieldcolors[TRACK]); if(!show_speeds) return; if(t->speed[0] + t->speed[1] + t->speed[2] + t->speed[3]) draw_pixmap(t->x, t->y, speed_pmap); } void switch_draw(Track *t) { int fg; int tmp; fg = t->fgcolor; switch(t->status) { case ST_FREE: break; case ST_BUSY: fg = color_red; break; case ST_READY: fg = color_green; break; case ST_WORK: fg = color_blue; } tmp = t->direction; switch(tmp) { case 0: if(editing) { t->direction = W_NE; track_draw(t); t->direction = W_E; track_draw(t); } else if(t->switched) { t->direction = W_NE; track_draw(t); } else t->direction = W_E; track_draw(t); break; case 1: if(editing) { t->direction = NW_E; track_draw(t); t->direction = W_E; track_draw(t); } else if(t->switched) { t->direction = NW_E; track_draw(t); } else t->direction = W_E; track_draw(t); break; case 2: if(editing) { t->direction = W_SE; track_draw(t); t->direction = W_E; track_draw(t); } else if(t->switched) { t->direction = W_SE; track_draw(t); } else t->direction = W_E; track_draw(t); break; case 3: if(editing) { t->direction = SW_E; track_draw(t); t->direction = W_E; track_draw(t); } else if(t->switched) { t->direction = SW_E; track_draw(t); } else t->direction = W_E; track_draw(t); break; case 4: if(editing) { t->direction = SW_E; track_draw(t); t->direction = SW_NE; } else if(t->switched) t->direction = SW_E; else t->direction = SW_NE; track_draw(t); break; case 5: if(editing) { t->direction = W_NE; track_draw(t); t->direction = SW_NE; } else if(t->switched) t->direction = W_NE; else t->direction = SW_NE; track_draw(t); break; case 6: if(editing) { t->direction = NW_E; track_draw(t); t->direction = NW_SE; } else if(t->switched) { t->direction = NW_E; } else t->direction = NW_SE; track_draw(t); break; case 7: if(editing) { t->direction = W_SE; track_draw(t); t->direction = NW_SE; } else if(t->switched) t->direction = W_SE; else t->direction = NW_SE; track_draw(t); break; case 8: if(t->switched && !editing) draw_layout(t->x, t->y, sweng_sw_ne_switched, fg); else draw_layout(t->x, t->y, sweng_sw_ne_straight, fg); break; case 9: if(t->switched && !editing) draw_layout(t->x, t->y, sweng_nw_se_switched, fg); else draw_layout(t->x, t->y, sweng_nw_se_straight, fg); break; case 10: if(editing) { t->direction = W_SE; track_draw(t); t->direction = W_NE; } else if (t->switched) t->direction = W_SE; else t->direction = W_NE; track_draw(t); break; case 11: if(editing) { t->direction = SW_E; track_draw(t); t->direction = NW_E; } else if (t->switched) t->direction = SW_E; else t->direction = NW_E; track_draw(t); break; case 12: if(editing) { t->direction = TRK_N_S; track_draw(t); t->direction = SW_N; } else if(t->switched) t->direction = SW_N; else t->direction = TRK_N_S; track_draw(t); break; case 13: if(editing) { t->direction = TRK_N_S; track_draw(t); t->direction = SE_N; } else if(t->switched) t->direction = SE_N; else t->direction = TRK_N_S; track_draw(t); break; case 14: if(editing) { t->direction = TRK_N_S; track_draw(t); t->direction = NW_S; } else if(t->switched) t->direction = NW_S; else t->direction = TRK_N_S; track_draw(t); break; case 15: if(editing) { t->direction = TRK_N_S; track_draw(t); t->direction = NE_S; } else if(t->switched) t->direction = NE_S; else t->direction = TRK_N_S; track_draw(t); break; } if(!t->norect) draw_layout(t->x, t->y, switch_rect, fieldcolors[TRACK]); t->direction = tmp; } void platform_draw(Track *t) { switch(t->direction) { case W_E: draw_layout(t->x, t->y, w_e_platform_out, fieldcolors[TRACK]); draw_layout(t->x, t->y, w_e_platform_in, color_darkgray); break; case N_S: draw_layout(t->x, t->y, n_s_platform_out, fieldcolors[TRACK]); draw_layout(t->x, t->y, n_s_platform_in, color_darkgray); break; } } void signal_draw(Track *t) { grcolor color = color_red; int i; i = 0; /* RR */ if(t->fleeted) { if(t->status == ST_GREEN) { if(t->nowfleeted) i = 2; /* GG */ else i = 1; /* GR */ } else if(t->nowfleeted) i = 3; /* RO */ draw_pixmap(t->x, t->y, signal_traditional ? (t->direction == W_E ? e_sig2_pmap[i] : w_sig2_pmap[i]) : (t->direction == W_E ? e_sigP_pmap[i] : w_sigP_pmap[i])); return; } if(t->status == ST_GREEN) i = 1; draw_pixmap(t->x, t->y, t->direction == W_E ? e_sig_pmap[i] : w_sig_pmap[i]); } void train_draw(Track *t, Train *trn) { if(!e_train_pmap[0]) { init_pmaps(); } if(trn->direction == W_E) draw_pixmap(t->x, t->y, e_train_pmap[trn->type]); else draw_pixmap(t->x, t->y, w_train_pmap[trn->type]); } void text_draw(Track *t) { if(!t->station) return; tr_fillrect(t->x, t->y); draw_layout_text(t->x, t->y, t->station); } void link_draw(Track *t) { tr_fillrect(t->x, t->y); if(t->direction == W_E) draw_layout_text(t->x, t->y, "...to..."); else draw_layout_text(t->x, t->y, "Link..."); } void macro_draw(Track *t) { tr_fillrect(t->x, t->y); if(t->direction == 0) draw_layout_text(t->x, t->y, "Macro"); else draw_layout_text(t->x, t->y, "Place"); } void image_draw(Track *t) { char buff[256]; if(!camera_pmap) camera_pmap = get_pixmap(camera_xpm); if(t->direction || !t->station) { /* filename! */ if(!t->pixels) t->pixels = camera_pmap; } else if(!t->pixels) { t->pixels = get_pixmap_file(t->station); if(!t->pixels) { sprintf(buff, "Error reading '%s'.", t->station); do_alert(buff); t->pixels = camera_pmap; } } draw_pixmap(t->x, t->y, t->pixels); } void track_paint(Track *t) { tr_fillrect(t->x, t->y); switch(t->type) { case TRACK: track_draw(t); break; case SWITCH: switch_draw(t); break; case PLATFORM: platform_draw(t); break; case TSIGNAL: signal_draw(t); break; case TRAIN: /* trains are handled differently */ /* train_draw(t); */ break; case TEXT: text_draw(t); break; case LINK: link_draw(t); break; case IMAGE: image_draw(t); break; case MACRO: macro_draw(t); break; default: return; } } char *train_next_stop(Train *t, int *final) { Track *tr; static char buff[256]; TrainStop *ts, *last; *final = 0; if(t->status != train_RUNNING && t->status != train_WAITING && t->status != train_STOPPED) return ""; buff[0] = 0; last = 0; for(ts = t->stops; ts; ts = ts->next) { if(!(tr = findStation(ts->station)) || tr->type != TRACK) continue; if(ts->stopped) continue; if(!last || ts->arrival < last->arrival) last = ts; } if(!last) { tr = findStation(t->exit); if(!tr || tr->type == TEXT) return ""; *final = 1; sprintf(buff, " Final stop %s at %s ", t->exit, format_time(t->timeout)); } else sprintf(buff, " Next stop %s at %s ", last->station, format_time(last->arrival)); return buff; } char *train_status0(Train *t, int full) { static char buff[256]; int i, j, k, final; if(terse_status) full = 0; buff[0] = 0; i = 0; switch(t->status) { case train_READY: if(!t->days || !run_day || (t->days & run_day)) return "ready"; sprintf(buff, "Canceled - runs on "); k = strlen(buff); for(i = 1, j = '1'; i < 0x80; i <<= 1, ++j) if(t->days & i) buff[k++] = j; buff[k] = 0; return buff; case train_RUNNING: if(full) strcpy(buff, train_next_stop(t, &final)); if(t->shunting) strcpy(buff + strlen(buff), "Shunting"); else if(full) { if(final) sprintf(buff + strlen(buff), "Speed: %d Km/h", t->curspeed); else sprintf(buff + strlen(buff), "Speed: %d Km/h to %s", t->curspeed, t->exit); } else sprintf(buff + strlen(buff), "Running. Dest %s", t->exit); return buff; case train_STOPPED: if(full) { sprintf(buff, "Stopped. ETD %s ", format_time(t->timedep)); if(full) strcat(buff, train_next_stop(t, &final)); if(!final) { strcat(buff, "Dest "); strcat(buff, t->exit); } } else sprintf(buff, "Stopped. ETD %s Dest %s", format_time(t->timedep), t->exit); return buff; case train_DELAY: sprintf(buff, "Delayed entry at %s", t->entrance); return buff; case train_WAITING: sprintf(buff, "Waiting. %sDest %s", full ? train_next_stop(t, &final) : "", t->exit); return buff; case train_DERAILED: return "derailed"; case train_ARRIVED: if(t->wrongdest) sprintf(buff, "Arrived at %s instead of %s", t->exited, t->exit); else if(t->timeexited / 60 > t->timeout / 60) sprintf(buff, "Arrived %d min. late at %s", (t->timeexited - t->timeout) / 60, t->exit); else sprintf(buff, "Arrived on time"); if(t->stock) { strcat(buff, " - stock for "); strcat(buff, t->stock); } return buff; } return ""; } char *train_status(Train *t) { return train_status0(t, 0); } void walk_vertical(Track *trk, Track *t, trkdir *ndir) { if(*ndir == N_S) { if(t->elinkx && t->elinky) { trk->x = t->elinkx; trk->y = t->elinky; return; } trk->x = t->x; trk->y = t->y + 1; return; } if(t->wlinkx && t->wlinky) { trk->x = t->wlinkx; trk->y = t->wlinky; return; } trk->x = t->x; trk->y = t->y - 1; } void walk_vertical_switch(Track *trk, Track *t, trkdir *ndir) { switch(t->direction) { case 12: if(*ndir == W_E) *ndir = S_N; if(*ndir == S_N) { trk->x = t->x; trk->y = t->y - 1; } else if(t->switched) { trk->x = t->x - 1; trk->y = t->y + 1; *ndir = E_W; } else { trk->x = t->x; trk->y = t->y + 1; } break; case 13: if(*ndir == E_W) *ndir = S_N; if(*ndir == S_N) { trk->x = t->x; trk->y = t->y - 1; } else if(t->switched) { trk->x = t->x + 1; trk->y = t->y + 1; *ndir = W_E; } else { trk->x = t->x; trk->y = t->y + 1; } break; case 14: if(*ndir == W_E) *ndir = N_S; if(*ndir == N_S) { trk->x = t->x; trk->y = t->y + 1; } else if(t->switched) { trk->x = t->x - 1; trk->y = t->y - 1; *ndir = E_W; } else { trk->x = t->x; trk->y = t->y - 1; } break; case 15: if(*ndir == E_W) *ndir = N_S; if(*ndir == N_S) { trk->x = t->x; trk->y = t->y + 1; } else if(t->switched) { trk->x = t->x + 1; trk->y = t->y - 1; *ndir = W_E; } else { trk->x = t->x; trk->y = t->y - 1; } break; } } Track *track_walkeast(Track *t, trkdir *ndir) { static Track trk; if(t->direction != TRK_N_S && t->elinkx && t->elinky) { trk.x = t->elinkx; trk.y = t->elinky; return &trk; } trk.x = t->x + 1; trk.y = t->y; switch(t->direction) { case NW_SE: case W_SE: ++trk.y; break; case SW_NE: case W_NE: --trk.y; break; case SW_N: if(*ndir == N_S) { trk.x = t->x - 1; trk.y = t->y + 1; *ndir = E_W; break; } trk.y = t->y - 1; trk.x = t->x; *ndir = S_N; break; case NW_S: if(*ndir == S_N) { *ndir = E_W; trk.x = t->x - 1; trk.y = t->y - 1; break; } trk.x = t->x; trk.y = t->y + 1; *ndir = N_S; break; case NE_S: if(*ndir == S_N) { *ndir = W_E; trk.x = t->x + 1; trk.y = t->y - 1; break; } trk.x = t->x; trk.y = t->y + 1; *ndir = N_S; break; case SE_N: if(*ndir == N_S) { trk.x = t->x + 1; trk.y = t->y + 1; *ndir = W_E; break; } trk.y = t->y - 1; trk.x = t->x; *ndir = S_N; break; case TRK_N_S: walk_vertical(&trk, t, ndir); break; } return &trk; } Track *track_walkwest(Track *t, trkdir *ndir) { static Track trk; if(t->direction != TRK_N_S && t->wlinkx && t->wlinky) { trk.x = t->wlinkx; trk.y = t->wlinky; return &trk; } trk.x = t->x - 1; trk.y = t->y; switch(t->direction) { case SW_N: if(*ndir == N_S) { ++trk.y; *ndir = E_W; break; } *ndir = S_N; case SW_NE: case SW_E: ++trk.y; break; case NW_S: if(*ndir == N_S) { trk.x = t->x; trk.y = t->y + 1; break; } *ndir = E_W; case NW_SE: case NW_E: --trk.y; break; case NE_S: if(*ndir == S_N) { trk.x = t->x + 1; trk.y = t->y - 1; *ndir = W_E; break; } *ndir = N_S; trk.y = t->y + 1; trk.x = t->x; break; case SE_N: if(*ndir == N_S) { trk.x = t->x + 1; trk.y = t->y + 1; *ndir = W_E; break; } *ndir = S_N; trk.x = t->x; trk.y = t->y - 1; break; case TRK_N_S: walk_vertical(&trk, t, ndir); break; } return &trk; } Track *swtch_walkeast(Track *t, trkdir *ndir) { static Track trk; trk.x = t->x; trk.y = t->y; switch(t->direction) { case 0: ++trk.x; if(t->switched) --trk.y; break; case 1: case 3: case 11: ++trk.x; break; case 2: ++trk.x; if(t->switched) ++trk.y; break; case 4: ++trk.x; if(!t->switched) --trk.y; break; case 5: ++trk.x; --trk.y; break; case 6: ++trk.x; if(!t->switched) ++trk.y; break; case 7: ++trk.x; ++trk.y; break; /* case 8: These are special cases handled in findPath() case 9: */ case 10: ++trk.x; if(t->switched) ++trk.y; else --trk.y; break; case 12: case 13: case 14: case 15: walk_vertical_switch(&trk, t, ndir); } return &trk; } Track *swtch_walkwest(Track *t, trkdir *ndir) { static Track trk; trk.x = t->x; trk.y = t->y; switch(t->direction) { case 1: --trk.x; if(t->switched) --trk.y; break; case 0: case 2: case 10: --trk.x; break; case 3: --trk.x; if(t->switched) ++trk.y; break; case 4: --trk.x; ++trk.y; break; case 5: --trk.x; if(!t->switched) ++trk.y; break; case 7: --trk.x; if(!t->switched) --trk.y; break; case 6: --trk.x; --trk.y; break; /* case 8: These are special cases handled in findPath() case 9: */ case 11: --trk.x; if(t->switched) ++trk.y; else --trk.y; break; case 12: case 13: case 14: case 15: walk_vertical_switch(&trk, t, ndir); } return &trk; } void check_layout_errors(void) { Track *t, *t1; char buff[256]; int firsttime = 1; for(t = layout; t; t = t->next) { buff[0] = 0; if(t->type == TSIGNAL) { if(!t->controls) sprintf(buff, "Signal at %d,%d not linked to any track.\n", t->x, t->y); else if(t->direction == E_W || t->direction == signal_WEST_FLEETED) { if(!t->controls->wsignal) sprintf(buff, "Track at %d,%d - not controlled by signal at %d,%d.\n", t->x, t->y, t->controls->x, t->controls->y); } else { if(!t->controls->esignal) sprintf(buff, "Track at %d,%d - not controlled by signal at %d,%d.\n", t->x, t->y, t->controls->x, t->controls->y); } } if(t->type == TRACK) { if(t->wlinkx && t->wlinky) { if(!(t1 = findTrack(t->wlinkx, t->wlinky))) sprintf(buff, "Track %d,%d linked to non-existant track at %d,%d.\n", t->x, t->y, t->wlinkx, t->wlinky); else if(!findTrack(t1->elinkx, t1->elinky) && !findTrack(t1->wlinkx, t1->wlinky)) sprintf(buff, "Track %d,%d not linked back to %d,%d.\n", t1->x, t1->y, t->x, t->y); } else if(t->elinkx && t->elinky) { if(!(t1 = findTrack(t->elinkx, t->elinky))) sprintf(buff, "Track %d,%d linked to non-existant track at %d,%d.\n", t->x, t->y, t->elinkx, t->elinky); else if(!findTrack(t1->elinkx, t1->elinky) && !findTrack(t1->wlinkx, t1->wlinky)) sprintf(buff, "Track %d,%d not linked back to %d,%d.\n", t1->x, t1->y, t->x, t->y); } } if(t->type == SWITCH) { if(t->wlinkx && t->wlinky) { if(!(t1 = findSwitch(t->wlinkx, t->wlinky))) sprintf(buff, "Switch %d,%d linked to non-existant switch at %d,%d.\n", t->x, t->y, t->wlinkx, t->wlinky); else if(t1->wlinkx != t->x || t1->wlinky != t->y) sprintf(buff, "Switch %d,%d not linked back to switch at %d,%d.\n", t1->x, t1->y, t->x, t->y); } } if(buff[0]) { if(firsttime) layout_error("Checking for errors in layout...\n"); firsttime = 0; layout_error(buff); } } end_layout_error(); } void link_tracks(Track *t, Track *t1) { switch(t->type) { case TRACK: if(t1->type != TRACK) { error("Only like tracks can be linked."); return; } if(t1->direction != W_E && t1->direction != TRK_N_S) { error("Only horizontal or vertical tacks can be linked automatically.\nTo link other track types, use the track properties dialog."); return; } /* if(t->direction != t1->direction) { error("You can't link horizontal to vertical tracks."); return; } */ if(t->direction == TRK_N_S) { if(!findTrack(t->x, t->y + 1)) { t->elinkx = t1->x; t->elinky = t1->y; } else { t->wlinkx = t1->x; t->wlinky = t1->y; } if(!findTrack(t1->x , t1->y + 1)) { t1->elinkx = t->x; t1->elinky = t->y; } else { t1->wlinkx = t->x; t1->wlinky = t->y; } break; } if(!findTrack(t->x + 1, t->y) && !findSwitch(t->x + 1, t->y)) { t->elinkx = t1->x; t->elinky = t1->y; } else { t->wlinkx = t1->x; t->wlinky = t1->y; } if(!findTrack(t1->x - 1, t1->y) && !findSwitch(t1->x - 1, t1->y)) { t1->wlinkx = t->x; t1->wlinky = t->y; } else { t1->elinkx = t->x; t1->elinky = t->y; } break; case SWITCH: if(t1->type != SWITCH) { error("Only like tracks can be linked."); return; } t->wlinkx = t1->x; t->wlinky = t1->y; t1->wlinkx = t->x; t1->wlinky = t->y; break; case TSIGNAL: if(t1->type != TRACK) { error("Signals can only be linked to a track."); return; } t->wlinkx = t1->x; t->wlinky = t1->y; break; case TEXT: if(t1->type != TRACK) { error("Entry/Exit points can only be linked to a track."); return; } if(t1->x < t->x) { t->wlinkx = t1->x; t->wlinky = t1->y; } else { t->elinkx = t1->x; t->elinky = t1->y; } break; } } int macro_select(void) { Track *t; char buff[256]; if(!macros) { maxmacros = 1; macros = (Track **)calloc(sizeof(Track *), maxmacros); } buff[0] = 0; if(!openFileDialog(buff)) return 0; remove_ext(buff); if(!(t = load_field(buff))) return 0; if(current_macro_name) free(current_macro_name); current_macro_name = strdup(buff); clean_field(t); /* if(macros[0]) clean_field(macros[0]); macros[0] = t; current_macro = 0; nmacros = 1; maxmacros = 1; */ return 1; } void macro_place(int xbase, int ybase) { Track *mp; Track *t, *t1; int x, y; int oldtool; if(!current_macro_name) return; oldtool = current_tool; mp = load_field(current_macro_name); while(mp) { t1 = mp->next; x = mp->x + xbase; y = mp->y + ybase; if((t = findTrack(x, y)) || (t = findSwitch(x, y)) || (t = findSignal(x, y)) || (t = findText(x, y)) || (t = findPlatform(x, y)) || (t = findImage(x, y))) { track_delete(t); } mp->x = x; mp->y = y; if(mp->elinkx && mp->elinky) { mp->elinkx += xbase; mp->elinky += ybase; } if(mp->wlinkx && mp->wlinky) { mp->wlinkx += xbase; mp->wlinky += ybase; } mp->next = layout; layout = mp; mp = t1; } invalidate_field(); repaint_all(); current_tool = oldtool; } void track_place(int x, int y) { Track *t, *t1; int needall; if(current_tool >= 0 && tooltbl[current_tool].type == MACRO) { if(!current_macro_name || tooltbl[current_tool].direction == 0) { select_tool(current_tool - 1); return; } macro_place(x, y); return; } if(current_tool >= 0 && tooltbl[current_tool].type == LINK) { if(tooltbl[current_tool].direction == 0) { if(!findTrack(x, y) && !findSignal(x, y) && !findSwitch(x, y) && !findText(x, y)) return; /* there must be a track */ link_startx = x; link_starty = y; select_tool(current_tool + 1); return; } if(link_startx == -1) { select_tool(current_tool - 1); return; } if(!(t = findTrack(link_startx, link_starty)) && !(t = findSwitch(link_startx, link_starty)) && !(t = findSignal(link_startx, link_starty)) && !(t = findText(link_startx, link_starty))) { return; } if(!(t1 = findTrack(x, y)) && !(t1 = findSignal(x, y)) && !(t1 = findSwitch(x, y)) && !(t1 = findText(x, y))) { return; } link_startx = -1; link_starty = -1; link_tracks(t, t1); select_tool(current_tool - 1); return; } needall = 0; if((t = findTrack(x, y)) || (t = findSwitch(x, y)) || (t = findSignal(x, y)) || (t = findText(x, y)) || (t = findPlatform(x, y)) || (t = findImage(x, y))) { needall = 1; track_delete(t); } if(current_tool == 0) { /* delete element */ repaint_all(); return; } t = track_new(); t->x = x; t->y = y; t->type = tooltbl[current_tool].type; t->direction = tooltbl[current_tool].direction; t->next = layout; if(t->type == TEXT) t->station = strdup("Abc"); else if(t->type == IMAGE) t->direction = 0; else if(t->type == TSIGNAL) { if(t->direction & 2) { t->fleeted = 1; t->direction &= ~2; } else t->fleeted = 0; if(auto_link) { x = t->x; y = t->y; if(t->direction == W_E) { ++y; } else { --y; } t1 = findTrack(x, y); if(t1 && t1->type == TRACK && t1->direction == W_E) link_tracks(t, t1); } } layout = t; if(needall) repaint_all(); else track_paint(t); } void track_properties(int x, int y) { Track *t; if((t = findTrack(x, y)) || (t = findText(x, y)) || (t = findSignal(x, y)) || (t = findImage(x, y))) { track_dialogue(t); /* This uses the native Windows dialog -> track_properties_dialog(t);*/ } }