/* Emacs style mode select -*- C++ -*- *----------------------------------------------------------------------------- * * * PrBoom a Doom port merged with LxDoom and LSDLDoom * based on BOOM, a modified and improved DOOM engine * Copyright (C) 1999 by * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman * Copyright (C) 1999-2000 by * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze * * 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., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * DESCRIPTION: * the automap code * *----------------------------------------------------------------------------- */ #include "doomstat.h" #include "st_stuff.h" #include "r_main.h" #include "p_setup.h" #include "p_maputl.h" #include "w_wad.h" #include "v_video.h" #include "p_spec.h" #include "am_map.h" #include "dstrings.h" #include "d_deh.h" // Ty 03/27/98 - externalizations #include "g_game.h" #include "rockmacros.h" //jff 1/7/98 default automap colors added int mapcolor_back; // map background int mapcolor_grid; // grid lines color int mapcolor_wall; // normal 1s wall color int mapcolor_fchg; // line at floor height change color int mapcolor_cchg; // line at ceiling height change color int mapcolor_clsd; // line at sector with floor=ceiling color int mapcolor_rkey; // red key color int mapcolor_bkey; // blue key color int mapcolor_ykey; // yellow key color int mapcolor_rdor; // red door color (diff from keys to allow option) int mapcolor_bdor; // blue door color (of enabling one but not other ) int mapcolor_ydor; // yellow door color int mapcolor_tele; // teleporter line color int mapcolor_secr; // secret sector boundary color int mapcolor_exit; // jff 4/23/98 add exit line color int mapcolor_unsn; // computer map unseen line color int mapcolor_flat; // line with no floor/ceiling changes int mapcolor_sprt; // general sprite color int mapcolor_item; // item sprite color int mapcolor_frnd; // friendly sprite color int mapcolor_hair; // crosshair color int mapcolor_sngl; // single player arrow color int mapcolor_plyr[4] = { 112, 88, 64, 176 }; // colors for player arrows in multiplayer //jff 3/9/98 add option to not show secret sectors until entered int map_secret_after; //jff 4/3/98 add symbols for "no-color" for disable and "black color" for black #define NC 0 #define BC 247 // drawing stuff #define FB 0 // scale on entry #define INITSCALEMTOF (.2*FRACUNIT) // how much the automap moves window per tic in frame-buffer coordinates // moves 140 pixels in 1 second #define F_PANINC 4 // how much zoom-in per tic // goes to 2x in 1 second #define M_ZOOMIN ((int) (1.02*FRACUNIT)) // how much zoom-out per tic // pulls out to 0.5x in 1 second #define M_ZOOMOUT ((int) (FRACUNIT/1.02)) // translates between frame-buffer and map distances #define FTOM(x) FixedMul(((x)<<16),scale_ftom) #define MTOF(x) (FixedMul((x),scale_mtof)>>16) // translates between frame-buffer and map coordinates #define CXMTOF(x) (f_x + MTOF((x)-m_x)) #define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y))) typedef struct { int x, y; } fpoint_t; typedef struct { fpoint_t a, b; } fline_t; typedef struct { mpoint_t a, b; } mline_t; typedef struct { fixed_t slp, islp; } islope_t; // // The vector graphics for the automap. // A line drawing of the player pointing right, // starting from the middle. // #define R ((8*PLAYERRADIUS)/7) mline_t player_arrow[] = { { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/4 } }, // -----> { { R, 0 }, { R-R/2, -R/4 } }, { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } }; #undef R #define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t)) #define R ((8*PLAYERRADIUS)/7) mline_t cheat_player_arrow[] = { // killough 3/22/98: He's alive, Jim :) { { -R+R/8, 0 }, { R, 0 } }, // ----- { { R, 0 }, { R-R/2, R/4 } }, // -----> { { R, 0 }, { R-R/2, -R/4 } }, { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }, { { -R/10-R/6, R/4}, {-R/10-R/6, -R/4} }, // J { { -R/10-R/6, -R/4}, {-R/10-R/6-R/8, -R/4} }, { { -R/10-R/6-R/8, -R/4}, {-R/10-R/6-R/8, -R/8} }, { { -R/10, R/4}, {-R/10, -R/4}}, // F { { -R/10, R/4}, {-R/10+R/8, R/4}}, { { -R/10+R/4, R/4}, {-R/10+R/4, -R/4}}, // F { { -R/10+R/4, R/4}, {-R/10+R/4+R/8, R/4}}, }; #undef R #define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t)) #define R (FRACUNIT) mline_t triangle_guy[] = { { { (fixed_t)(-.867*R), (fixed_t)(-.5*R) }, { (fixed_t)( .867*R), (fixed_t)(-.5*R) } }, { { (fixed_t)( .867*R), (fixed_t)(-.5*R) }, { (fixed_t)(0 ), (fixed_t)( R) } }, { { (fixed_t)(0 ), (fixed_t)( R) }, { (fixed_t)(-.867*R), (fixed_t)(-.5*R) } } }; #undef R #define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t)) //jff 1/5/98 new symbol for keys on automap #define R (FRACUNIT) mline_t cross_mark[] = { { { -R, 0 }, { R, 0} }, { { 0, -R }, { 0, R } }, }; #undef R #define NUMCROSSMARKLINES (sizeof(cross_mark)/sizeof(mline_t)) //jff 1/5/98 end of new symbol #define R (FRACUNIT) mline_t thintriangle_guy[] = { { { (fixed_t)(-.5*R), (fixed_t)(-.7*R) }, { (fixed_t)( R), (fixed_t)( 0) } }, { { (fixed_t)( R), (fixed_t)( 0) }, { (fixed_t)(-.5*R), (fixed_t)( .7*R) } }, { { (fixed_t)(-.5*R), (fixed_t)( .7*R) }, { (fixed_t)(-.5*R), (fixed_t)(-.7*R) } } }; #undef R #define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t)) int ddt_cheating = 0; // killough 2/7/98: make global, rename to ddt_* static int leveljuststarted = 1; // kluge until AM_LevelInit() is called enum automapmode_e automapmode; // Mode that the automap is in // location of window on screen static int f_x; static int f_y; // size of window on screen static int f_w; static int f_h; static mpoint_t m_paninc; // how far the window pans each tic (map coords) static fixed_t mtof_zoommul; // how far the window zooms each tic (map coords) static fixed_t ftom_zoommul; // how far the window zooms each tic (fb coords) static fixed_t m_x, m_y; // LL x,y window location on the map (map coords) static fixed_t m_x2, m_y2; // UR x,y window location on the map (map coords) // // width/height of window on map (map coords) // static fixed_t m_w; static fixed_t m_h; // based on level size static fixed_t min_x; static fixed_t min_y; static fixed_t max_x; static fixed_t max_y; static fixed_t max_w; // max_x-min_x, static fixed_t max_h; // max_y-min_y // based on player size static fixed_t min_w; static fixed_t min_h; static fixed_t min_scale_mtof; // used to tell when to stop zooming out static fixed_t max_scale_mtof; // used to tell when to stop zooming in // old stuff for recovery later static fixed_t old_m_w, old_m_h; static fixed_t old_m_x, old_m_y; // old location used by the Follower routine static mpoint_t f_oldloc; // used by MTOF to scale from map-to-frame-buffer coords static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF; // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof) static fixed_t scale_ftom; static player_t *plr; // the player represented by an arrow // killough 2/22/98: Remove limit on automap marks, // and make variables external for use in savegames. mpoint_t *markpoints = NULL; // where the points are int markpointnum = 0; // next point to be assigned (also number of points now) int markpointnum_max = 0; // killough 2/22/98 static boolean stopped = true; // // AM_getIslope() // // Calculates the slope and slope according to the x-axis of a line // segment in map coordinates (with the upright y-axis n' all) so // that it can be used with the brain-dead drawing stuff. // // Passed the line slope is desired for and an islope_t structure for return // Returns nothing // void AM_getIslope ( mline_t* ml, islope_t* is ) { int dx, dy; dy = ml->a.y - ml->b.y; dx = ml->b.x - ml->a.x; if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX); else is->islp = FixedDiv(dx, dy); if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX); else is->slp = FixedDiv(dy, dx); } // // AM_activateNewScale() // // Changes the map scale after zooming or translating // // Passed nothing, returns nothing // void AM_activateNewScale(void) { m_x += m_w/2; m_y += m_h/2; m_w = FTOM(f_w); m_h = FTOM(f_h); m_x -= m_w/2; m_y -= m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; } // // AM_saveScaleAndLoc() // // Saves the current center and zoom // Affects the variables that remember old scale and loc // // Passed nothing, returns nothing // void AM_saveScaleAndLoc(void) { old_m_x = m_x; old_m_y = m_y; old_m_w = m_w; old_m_h = m_h; } // // AM_restoreScaleAndLoc() // // restores the center and zoom from locally saved values // Affects global variables for location and scale // // Passed nothing, returns nothing // void AM_restoreScaleAndLoc(void) { m_w = old_m_w; m_h = old_m_h; if (!(automapmode & am_follow)) { m_x = old_m_x; m_y = old_m_y; } else { m_x = plr->mo->x - m_w/2; m_y = plr->mo->y - m_h/2; } m_x2 = m_x + m_w; m_y2 = m_y + m_h; // Change the scaling multipliers scale_mtof = FixedDiv(f_w<= markpointnum_max) markpoints = realloc(markpoints, (markpointnum_max = markpointnum_max ? markpointnum_max*2 : 16) * sizeof(*markpoints)); markpoints[markpointnum].x = m_x + m_w/2; markpoints[markpointnum].y = m_y + m_h/2; markpointnum++; } // // AM_findMinMaxBoundaries() // // Determines bounding box of all vertices, // sets global variables controlling zoom range. // // Passed nothing, returns nothing // void AM_findMinMaxBoundaries(void) { int i; fixed_t a; fixed_t b; min_x = min_y = INT_MAX; max_x = max_y = -INT_MAX; for (i=0;i max_x) max_x = vertexes[i].x; if (vertexes[i].y < min_y) min_y = vertexes[i].y; else if (vertexes[i].y > max_y) max_y = vertexes[i].y; } max_w = max_x - min_x; max_h = max_y - min_y; min_w = 2*PLAYERRADIUS; // const? never changed? min_h = 2*PLAYERRADIUS; a = FixedDiv(f_w< max_x) m_x = max_x - m_w/2; else if (m_x + m_w/2 < min_x) m_x = min_x - m_w/2; if (m_y + m_h/2 > max_y) m_y = max_y - m_h/2; else if (m_y + m_h/2 < min_y) m_y = min_y - m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; } // // AM_initVariables() // // Initialize the variables for the automap // // Affects the automap global variables // Status bar is notified that the automap has been entered // Passed nothing, returns nothing // void AM_initVariables(void) { int pnum; static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0 , 0 }; automapmode |= am_active; f_oldloc.x = INT_MAX; m_paninc.x = m_paninc.y = 0; ftom_zoommul = FRACUNIT; mtof_zoommul = FRACUNIT; m_w = FTOM(f_w); m_h = FTOM(f_h); // find player to center on initially if (!playeringame[pnum = consoleplayer]) for (pnum=0;pnummo->x - m_w/2; m_y = plr->mo->y - m_h/2; AM_changeWindowLoc(); // for saving & restoring old_m_x = m_x; old_m_y = m_y; old_m_w = m_w; old_m_h = m_h; // inform the status bar of the change ST_Responder(&st_notify); } // // AM_loadPics() // void AM_loadPics(void) { // cph - mark numbers no longer needed cached } // // AM_unloadPics() // void AM_unloadPics(void) { // cph - mark numbers no longer needed cached } // // AM_clearMarks() // // Sets the number of marks to 0, thereby clearing them from the display // // Affects the global variable markpointnum // Passed nothing, returns nothing // void AM_clearMarks(void) { markpointnum = 0; } // // AM_LevelInit() // // Initialize the automap at the start of a new level // should be called at the start of every level // // Passed nothing, returns nothing // Affects automap's global variables // // CPhipps - get status bar height from status bar code void AM_LevelInit(void) { leveljuststarted = 0; f_x = f_y = 0; f_w = SCREENWIDTH; // killough 2/7/98: get rid of finit_ vars f_h = SCREENHEIGHT-ST_SCALED_HEIGHT;// to allow runtime setting of width/height AM_findMinMaxBoundaries(); scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT)); if (scale_mtof > max_scale_mtof) scale_mtof = min_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); } // // AM_Stop() // // Cease automap operations, unload patches, notify status bar // // Passed nothing, returns nothing // void AM_Stop (void) { static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 }; AM_unloadPics(); automapmode &= ~am_active; ST_Responder(&st_notify); stopped = true; } // // AM_Start() // // Start up automap operations, // if a new level, or game start, (re)initialize level variables // init map variables // load mark patches // // Passed nothing, returns nothing // void AM_Start() { static int lastlevel = -1, lastepisode = -1; if (!stopped) AM_Stop(); stopped = false; if (lastlevel != gamemap || lastepisode != gameepisode) { AM_LevelInit(); lastlevel = gamemap; lastepisode = gameepisode; } AM_initVariables(); AM_loadPics(); } // // AM_minOutWindowScale() // // Set the window scale to the maximum size // // Passed nothing, returns nothing // void AM_minOutWindowScale() { scale_mtof = min_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); AM_activateNewScale(); } // // AM_maxOutWindowScale(void) // // Set the window scale to the minimum size // // Passed nothing, returns nothing // void AM_maxOutWindowScale(void) { scale_mtof = max_scale_mtof; scale_ftom = FixedDiv(FRACUNIT, scale_mtof); AM_activateNewScale(); } // // AM_Responder() // // Handle events (user inputs) in automap mode // // Passed an input event, returns true if its handled // boolean AM_Responder ( event_t* ev ) { int rc; static int cheatstate=0; static int bigstate=0; static char buffer[20]; int ch; // phares rc = false; if (!(automapmode & am_active)) { if (ev->type == ev_keydown && ev->data1 == key_map) // phares { AM_Start (); rc = true; } } else if (ev->type == ev_keydown) { rc = true; ch = ev->data1; // phares if (ch == key_map_right) // | if (!(automapmode & am_follow)) // V m_paninc.x = FTOM(F_PANINC); else rc = false; else if (ch == key_map_left) if (!(automapmode & am_follow)) m_paninc.x = -FTOM(F_PANINC); else rc = false; else if (ch == key_map_up) if (!(automapmode & am_follow)) m_paninc.y = FTOM(F_PANINC); else rc = false; else if (ch == key_map_down) if (!(automapmode & am_follow)) m_paninc.y = -FTOM(F_PANINC); else rc = false; else if (ch == key_map_zoomout) { mtof_zoommul = M_ZOOMOUT; ftom_zoommul = M_ZOOMIN; } else if (ch == key_map_zoomin) { mtof_zoommul = M_ZOOMIN; ftom_zoommul = M_ZOOMOUT; } else if (ch == key_map) { bigstate = 0; AM_Stop (); } else if (ch == key_map_gobig) { bigstate = !bigstate; if (bigstate) { AM_saveScaleAndLoc(); AM_minOutWindowScale(); } else AM_restoreScaleAndLoc(); } else if (ch == key_map_follow) { automapmode ^= am_follow; // CPhipps - put all automap mode stuff into one enum f_oldloc.x = INT_MAX; // Ty 03/27/98 - externalized plr->message = (automapmode & am_follow) ? s_AMSTR_FOLLOWON : s_AMSTR_FOLLOWOFF; } else if (ch == key_map_grid) { automapmode ^= am_grid; // CPhipps // Ty 03/27/98 - *not* externalized plr->message = (automapmode & am_grid) ? s_AMSTR_GRIDON : s_AMSTR_GRIDOFF; } else if (ch == key_map_mark) { // Ty 03/27/98 - *not* externalized snprintf(buffer, sizeof(buffer), "%s %d", s_AMSTR_MARKEDSPOT, markpointnum); plr->message = buffer; AM_addMark(); } else if (ch == key_map_clear) { AM_clearMarks(); // Ty 03/27/98 - *not* externalized plr->message = s_AMSTR_MARKSCLEARED; // ^ } // | else if (ch == key_map_rotate) { automapmode ^= am_rotate; plr->message = (automapmode & am_rotate) ? s_AMSTR_ROTATEON : s_AMSTR_ROTATEOFF; } else if (ch == key_map_overlay) { automapmode ^= am_overlay; plr->message = (automapmode & am_overlay) ? s_AMSTR_OVERLAYON : s_AMSTR_OVERLAYOFF; } else // phares { cheatstate=0; rc = false; } } else if (ev->type == ev_keyup) { rc = false; ch = ev->data1; if (ch == key_map_right) { if (!(automapmode & am_follow)) m_paninc.x = 0; } else if (ch == key_map_left) { if (!(automapmode & am_follow)) m_paninc.x = 0; } else if (ch == key_map_up) { if (!(automapmode & am_follow)) m_paninc.y = 0; } else if (ch == key_map_down) { if (!(automapmode & am_follow)) m_paninc.y = 0; } else if ((ch == key_map_zoomout) || (ch == key_map_zoomin)) { mtof_zoommul = FRACUNIT; ftom_zoommul = FRACUNIT; } } return rc; } // // AM_rotate() // // Rotation in 2D. // Used to rotate player arrow line character. // // Passed the coordinates of a point, and an angle // Returns the coordinates rotated by the angle // // CPhipps - made static & enhanced for automap rotation static void AM_rotate(fixed_t* x, fixed_t* y, angle_t a, fixed_t xorig, fixed_t yorig) { fixed_t tmpx; tmpx = FixedMul(*x - xorig,finecosine[a>>ANGLETOFINESHIFT]) - FixedMul(*y - yorig,finesine[a>>ANGLETOFINESHIFT]); *y = yorig + FixedMul(*x - xorig,finesine[a>>ANGLETOFINESHIFT]) + FixedMul(*y - yorig,finecosine[a>>ANGLETOFINESHIFT]); *x = tmpx + xorig; } // // AM_changeWindowScale() // // Automap zooming // // Passed nothing, returns nothing // void AM_changeWindowScale(void) { // Change the scaling multipliers scale_mtof = FixedMul(scale_mtof, mtof_zoommul); scale_ftom = FixedDiv(FRACUNIT, scale_mtof); if (scale_mtof < min_scale_mtof) AM_minOutWindowScale(); else if (scale_mtof > max_scale_mtof) AM_maxOutWindowScale(); else AM_activateNewScale(); } // // AM_doFollowPlayer() // // Turn on follow mode - the map scrolls opposite to player motion // // Passed nothing, returns nothing // void AM_doFollowPlayer(void) { if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y) { m_x = FTOM(MTOF(plr->mo->x)) - m_w/2; m_y = FTOM(MTOF(plr->mo->y)) - m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; f_oldloc.x = plr->mo->x; f_oldloc.y = plr->mo->y; } } // // AM_Ticker() // // Updates on gametic - enter follow mode, zoom, or change map location // // Passed nothing, returns nothing // void AM_Ticker (void) { if (!(automapmode & am_active)) return; if (automapmode & am_follow) AM_doFollowPlayer(); // Change the zoom if necessary if (ftom_zoommul != FRACUNIT) AM_changeWindowScale(); // Change x,y location if (m_paninc.x || m_paninc.y) AM_changeWindowLoc(); } // // AM_clipMline() // // Automap clipping of lines. // // Based on Cohen-Sutherland clipping algorithm but with a slightly // faster reject and precalculated slopes. If the speed is needed, // use a hash algorithm to handle the common cases. // // Passed the line's coordinates on map and in the frame buffer performs // clipping on them in the lines frame coordinates. // Returns true if any part of line was not clipped // boolean AM_clipMline ( mline_t* ml, fline_t* fl ) { enum { LEFT =1, RIGHT =2, BOTTOM =4, TOP =8 }; register int outcode1 = 0; register int outcode2 = 0; register int outside; fpoint_t tmp = {0,0}; int dx; int dy; #define DOOUTCODE(oc, mx, my) \ (oc) = 0; \ if ((my) < 0) (oc) |= TOP; \ else if ((my) >= f_h) (oc) |= BOTTOM; \ if ((mx) < 0) (oc) |= LEFT; \ else if ((mx) >= f_w) (oc) |= RIGHT; // do trivial rejects and outcodes if (ml->a.y > m_y2) outcode1 = TOP; else if (ml->a.y < m_y) outcode1 = BOTTOM; if (ml->b.y > m_y2) outcode2 = TOP; else if (ml->b.y < m_y) outcode2 = BOTTOM; if (outcode1 & outcode2) return false; // trivially outside if (ml->a.x < m_x) outcode1 |= LEFT; else if (ml->a.x > m_x2) outcode1 |= RIGHT; if (ml->b.x < m_x) outcode2 |= LEFT; else if (ml->b.x > m_x2) outcode2 |= RIGHT; if (outcode1 & outcode2) return false; // trivially outside // transform to frame-buffer coordinates. fl->a.x = CXMTOF(ml->a.x); fl->a.y = CYMTOF(ml->a.y); fl->b.x = CXMTOF(ml->b.x); fl->b.y = CYMTOF(ml->b.y); DOOUTCODE(outcode1, fl->a.x, fl->a.y); DOOUTCODE(outcode2, fl->b.x, fl->b.y); if (outcode1 & outcode2) return false; while (outcode1 | outcode2) { // may be partially inside box // find an outside point if (outcode1) outside = outcode1; else outside = outcode2; // clip to each side if (outside & TOP) { dy = fl->a.y - fl->b.y; dx = fl->b.x - fl->a.x; tmp.x = fl->a.x + (dx*(fl->a.y))/dy; tmp.y = 0; } else if (outside & BOTTOM) { dy = fl->a.y - fl->b.y; dx = fl->b.x - fl->a.x; tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy; tmp.y = f_h-1; } else if (outside & RIGHT) { dy = fl->b.y - fl->a.y; dx = fl->b.x - fl->a.x; tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx; tmp.x = f_w-1; } else if (outside & LEFT) { dy = fl->b.y - fl->a.y; dx = fl->b.x - fl->a.x; tmp.y = fl->a.y + (dy*(-fl->a.x))/dx; tmp.x = 0; } if (outside == outcode1) { fl->a = tmp; DOOUTCODE(outcode1, fl->a.x, fl->a.y); } else { fl->b = tmp; DOOUTCODE(outcode2, fl->b.x, fl->b.y); } if (outcode1 & outcode2) return false; // trivially outside } return true; } #undef DOOUTCODE // // AM_drawFline() // // Draw a line in the frame buffer. // Classic Bresenham w/ whatever optimizations needed for speed // // Passed the frame coordinates of line, and the color to be drawn // Returns nothing // void AM_drawFline ( fline_t* fl, int color ) { register int x; register int y; register int dx; register int dy; register int sx; register int sy; register int ax; register int ay; register int d; #ifdef RANGECHECK // killough 2/22/98 static int fuck = 0; // For debugging only if ( fl->a.x < 0 || fl->a.x >= f_w || fl->a.y < 0 || fl->a.y >= f_h || fl->b.x < 0 || fl->b.x >= f_w || fl->b.y < 0 || fl->b.y >= f_h ) { //jff 8/3/98 use logical output routine printf("fuck %d \r", fuck++); return; } #endif #define PUTDOT(xx,yy,cc) V_PlotPixel(FB,xx,yy,(byte)cc) dx = fl->b.x - fl->a.x; ax = 2 * (dx<0 ? -dx : dx); sx = dx<0 ? -1 : 1; dy = fl->b.y - fl->a.y; ay = 2 * (dy<0 ? -dy : dy); sy = dy<0 ? -1 : 1; x = fl->a.x; y = fl->a.y; if (ax > ay) { d = ay - ax/2; while (1) { PUTDOT(x,y,color); if (x == fl->b.x) return; if (d>=0) { y += sy; d -= ax; } x += sx; d += ay; } } else { d = ax - ay/2; while (1) { PUTDOT(x, y, color); if (y == fl->b.y) return; if (d >= 0) { x += sx; d -= ay; } y += sy; d += ax; } } } // // AM_drawMline() // // Clip lines, draw visible parts of lines. // // Passed the map coordinates of the line, and the color to draw it // Color -1 is special and prevents drawing. Color 247 is special and // is translated to black, allowing Color 0 to represent feature disable // in the defaults file. // Returns nothing. // void AM_drawMline ( mline_t* ml, int color ) { static fline_t fl; if (color==-1) // jff 4/3/98 allow not drawing any sort of line return; // by setting its color to -1 if (color==247) // jff 4/3/98 if color is 247 (xparent), use black color=0; if (AM_clipMline(ml, &fl)) AM_drawFline(&fl, color); // draws it on frame buffer using fb coords } // // AM_drawGrid() // // Draws blockmap aligned grid lines. // // Passed the color to draw the grid lines // Returns nothing // void AM_drawGrid(int color) { fixed_t x, y; fixed_t start, end; mline_t ml; // Figure out start of vertical gridlines start = m_x; if ((start-bmaporgx)%(MAPBLOCKUNITS<> LockedKeyShift; if (!type || type==7) return 3; //any or all keys else return (type-1)%3; } switch (type) // closed keyed door { case 26: case 32: case 99: case 133: /*bluekey*/ return 1; case 27: case 34: case 136: case 137: /*yellowkey*/ return 2; case 28: case 33: case 134: case 135: /*redkey*/ return 0; default: return -1; //not a keyed door } return -1; //not a keyed door } // // Determines visible lines, draws them. // This is LineDef based, not LineSeg based. // // jff 1/5/98 many changes in this routine // backward compatibility not needed, so just changes, no ifs // addition of clauses for: // doors opening, keyed door id, secret sectors, // teleports, exit lines, key things // ability to suppress any of added features or lines with no height changes // // support for gamma correction in automap abandoned // // jff 4/3/98 changed mapcolor_xxxx=0 as control to disable feature // jff 4/3/98 changed mapcolor_xxxx=-1 to disable drawing line completely // void AM_drawWalls(void) { int i; static mline_t l; // draw the unclipped visible portions of all lines for (i=0;ix; l.a.y = lines[i].v1->y; l.b.x = lines[i].v2->x; l.b.y = lines[i].v2->y; if (automapmode & am_rotate) { AM_rotate(&l.a.x, &l.a.y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); AM_rotate(&l.b.x, &l.b.y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); } // if line has been seen or IDDT has been used if (ddt_cheating || (lines[i].flags & ML_MAPPED)) { if ((lines[i].flags & ML_DONTDRAW) && !ddt_cheating) continue; { /* cph - show keyed doors and lines */ int amd; if ((mapcolor_bdor || mapcolor_ydor || mapcolor_rdor) && !(lines[i].flags & ML_SECRET) && /* non-secret */ (amd = AM_DoorColor(lines[i].special)) != -1 ) { { switch (amd) /* closed keyed door */ { case 1: /*bluekey*/ AM_drawMline(&l, mapcolor_bdor? mapcolor_bdor : mapcolor_cchg); continue; case 2: /*yellowkey*/ AM_drawMline(&l, mapcolor_ydor? mapcolor_ydor : mapcolor_cchg); continue; case 0: /*redkey*/ AM_drawMline(&l, mapcolor_rdor? mapcolor_rdor : mapcolor_cchg); continue; case 3: /*any or all*/ AM_drawMline(&l, mapcolor_clsd? mapcolor_clsd : mapcolor_cchg); continue; } } } } if /* jff 4/23/98 add exit lines to automap */ ( mapcolor_exit && ( lines[i].special==11 || lines[i].special==52 || lines[i].special==197 || lines[i].special==51 || lines[i].special==124 || lines[i].special==198 ) ) { AM_drawMline(&l, mapcolor_exit); /* exit line */ continue; } if (!lines[i].backsector) { // jff 1/10/98 add new color for 1S secret sector boundary if (mapcolor_secr && //jff 4/3/98 0 is disable ( ( map_secret_after && P_WasSecret(lines[i].frontsector) && !P_IsSecret(lines[i].frontsector) ) || ( !map_secret_after && P_WasSecret(lines[i].frontsector) ) ) ) AM_drawMline(&l, mapcolor_secr); // line bounding secret sector else //jff 2/16/98 fixed bug AM_drawMline(&l, mapcolor_wall); // special was cleared } else /* now for 2S lines */ { // jff 1/10/98 add color change for all teleporter types if ( mapcolor_tele && !(lines[i].flags & ML_SECRET) && (lines[i].special == 39 || lines[i].special == 97 || lines[i].special == 125 || lines[i].special == 126) ) { // teleporters AM_drawMline(&l, mapcolor_tele); } else if (lines[i].flags & ML_SECRET) // secret door { AM_drawMline(&l, mapcolor_wall); // wall color } else if ( mapcolor_clsd && !(lines[i].flags & ML_SECRET) && // non-secret closed door ((lines[i].backsector->floorheight==lines[i].backsector->ceilingheight) || (lines[i].frontsector->floorheight==lines[i].frontsector->ceilingheight)) ) { AM_drawMline(&l, mapcolor_clsd); // non-secret closed door } //jff 1/6/98 show secret sector 2S lines else if ( mapcolor_secr && //jff 2/16/98 fixed bug ( // special was cleared after getting it (map_secret_after && ( (P_WasSecret(lines[i].frontsector) && !P_IsSecret(lines[i].frontsector)) || (P_WasSecret(lines[i].backsector) && !P_IsSecret(lines[i].backsector)) ) ) || //jff 3/9/98 add logic to not show secret til after entered ( // if map_secret_after is true !map_secret_after && (P_WasSecret(lines[i].frontsector) || P_WasSecret(lines[i].backsector)) ) ) ) { AM_drawMline(&l, mapcolor_secr); // line bounding secret sector } //jff 1/6/98 end secret sector line change else if (lines[i].backsector->floorheight != lines[i].frontsector->floorheight) { AM_drawMline(&l, mapcolor_fchg); // floor level change } else if (lines[i].backsector->ceilingheight != lines[i].frontsector->ceilingheight) { AM_drawMline(&l, mapcolor_cchg); // ceiling level change } else if (mapcolor_flat && ddt_cheating) { AM_drawMline(&l, mapcolor_flat); //2S lines that appear only in IDDT } } } // now draw the lines only visible because the player has computermap else if (plr->powers[pw_allmap]) // computermap visible lines { if (!(lines[i].flags & ML_DONTDRAW)) // invisible flag lines do not show { if ( mapcolor_flat || !lines[i].backsector || lines[i].backsector->floorheight != lines[i].frontsector->floorheight || lines[i].backsector->ceilingheight != lines[i].frontsector->ceilingheight ) AM_drawMline(&l, mapcolor_unsn); } } } } // // AM_drawLineCharacter() // // Draws a vector graphic according to numerous parameters // // Passed the structure defining the vector graphic shape, the number // of vectors in it, the scale to draw it at, the angle to draw it at, // the color to draw it with, and the map coordinates to draw it at. // Returns nothing // void AM_drawLineCharacter ( mline_t* lineguy, int lineguylines, fixed_t scale, angle_t angle, int color, fixed_t x, fixed_t y ) { int i; mline_t l; if (automapmode & am_rotate) angle -= plr->mo->angle - ANG90; // cph for (i=0;imo->angle, mapcolor_sngl, //jff color plr->mo->x, plr->mo->y ); else AM_drawLineCharacter ( player_arrow, NUMPLYRLINES, 0, plr->mo->angle, mapcolor_sngl, //jff color plr->mo->x, plr->mo->y); return; } for (i=0;imo->x, y = p->mo->y; if (automapmode & am_rotate) AM_rotate(&x, &y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); AM_drawLineCharacter (player_arrow, NUMPLYRLINES, 0, p->mo->angle, p->powers[pw_invisibility] ? 246 /* *close* to black */ : mapcolor_plyr[i], //jff 1/6/98 use default color x, y); } } } // // AM_drawThings() // // Draws the things on the automap in double IDDT cheat mode // // Passed colors and colorrange, no longer used // Returns nothing // void AM_drawThings ( int colors, int colorrange) { (void)colors; (void)colorrange; int i; mobj_t* t; // for all sectors for (i=0;ix, y = t->y; if (automapmode & am_rotate) AM_rotate(&x, &y, ANG90-plr->mo->angle, plr->mo->x, plr->mo->y); //jff 1/5/98 case over doomednum of thing being drawn if (mapcolor_rkey || mapcolor_ykey || mapcolor_bkey) { switch(t->info->doomednum) { //jff 1/5/98 treat keys special case 38: case 13: //jff red key AM_drawLineCharacter ( cross_mark, NUMCROSSMARKLINES, 16<angle, mapcolor_rkey!=-1? mapcolor_rkey : mapcolor_sprt, x, y ); t = t->snext; continue; case 39: case 6: //jff yellow key AM_drawLineCharacter ( cross_mark, NUMCROSSMARKLINES, 16<angle, mapcolor_ykey!=-1? mapcolor_ykey : mapcolor_sprt, x, y ); t = t->snext; continue; case 40: case 5: //jff blue key AM_drawLineCharacter ( cross_mark, NUMCROSSMARKLINES, 16<angle, mapcolor_bkey!=-1? mapcolor_bkey : mapcolor_sprt, x, y ); t = t->snext; continue; default: break; } } //jff 1/5/98 end added code for keys //jff previously entire code AM_drawLineCharacter ( thintriangle_guy, NUMTHINTRIANGLEGUYLINES, 16<angle, t->flags & MF_FRIEND && !t->player ? mapcolor_frnd : /* bbm 2/28/03 Show countable items in yellow. */ t->flags & MF_COUNTITEM ? mapcolor_item : mapcolor_sprt, x, y ); t = t->snext; } } } // // AM_drawMarks() // // Draw the marked locations on the automap // // Passed nothing, returns nothing // // killough 2/22/98: // Rewrote AM_drawMarks(). Removed limit on marks. // void AM_drawMarks(void) { int i; for (i=0;imo->angle, plr->mo->x, plr->mo->y); fx = CXMTOF(fx); fy = CYMTOF(fy); do { int d = j % 10; if (d==1) // killough 2/22/98: less spacing for '1' fx++; if (fx >= f_x && fx < f_w - w && fy >= f_y && fy < f_h - h) { // cph - construct patch name and draw marker char namebuf[] = { 'A', 'M', 'M', 'N', 'U', 'M', '0'+d, 0 }; V_DrawNamePatch(fx, fy, FB, namebuf, CR_DEFAULT, VPT_NONE); } fx -= w-1; // killough 2/22/98: 1 space backwards j /= 10; } while (j>0); } } // // AM_drawCrosshair() // // Draw the single point crosshair representing map center // // Passed the color to draw the pixel with // Returns nothing // // CPhipps - made static inline, and use the general pixel plotter function inline static void AM_drawCrosshair(int color) { // single point for now V_PlotPixel(FB, f_w/2, f_h/2, (byte)color); } // // AM_Drawer() // // Draws the entire automap // // Passed nothing, returns nothing // void AM_Drawer (void) { // CPhipps - all automap modes put into one enum if (!(automapmode & am_active)) return; if (!(automapmode & am_overlay)) // cph - If not overlay mode, clear background for the automap V_FillRect(FB, f_x, f_y, f_w, f_h, (byte)mapcolor_back); //jff 1/5/98 background default color if (automapmode & am_grid) AM_drawGrid(mapcolor_grid); //jff 1/7/98 grid default color AM_drawWalls(); AM_drawPlayers(); if (ddt_cheating==2) AM_drawThings(mapcolor_sprt, 0); //jff 1/5/98 default double IDDT sprite AM_drawCrosshair(mapcolor_hair); //jff 1/7/98 default crosshair color AM_drawMarks(); V_MarkRect(f_x, f_y, f_w, f_h); } )è3+J tQ(p(枞c%w\ Jt޳j(y5nzRmx|8&\$Cu$PŌoL 㕫ֻR-i e=('-^\!T9m Ub]VP"pU*;e@RZ °mЊٯ߇ݙ_'g+0CKٙDpv9 DԠ3;ñ"nsfcnaʻ 6Q%Ppafi'B]+u"Vz+x'{nd\f]%FE5A}\_ uL(DZܮ9TVZqT >]})]BC 78sAR䳼)W@:y /x9*:B}sev(J``!Q[p5Bt1NW,Lv@`1bVmξ13q,Y[35$/->l)``2?;~r7߇%<ׁŒފflV>f2l3ZnƿfeŕfͲTrCU\Q8j YVyg]hέX7%tKc&rtm`)ܫlji,@UeP@%49q* w Q2ZX))wZO$pMjZŢ-5[]^ 5<QY`c*{qaw(M~/[Ű ҏ\L,nIjfQHPD|-̄)n v47%!AbB{FY,ұ.bfF)\%0;XD[߲Ebc rΨ 𺳣G74X2.+tj5{'?zڏa6H"Vɳh6N^LIaڙ#!} :`; }ڕqx&8} APɕ& _6?Oqn)ĹuKЇmۘ]hf:kP4 o^eQٖ {:}E'D/sM.p ~6ʹmbQRv6@}uy!&htCGSt؆WdR7Hy]+vHDf]= c.u; atySTo\Ph=UU798Vw*Cc6stXT˄s8N`\Z#b=h) e<+aoYKH*"ԡY V=L(AәOʨ\EB60Q (:VU`;G466_ꏩYmxX!ȍ}uX"Q-iZ#.WC̏Vu`:i"n)зJC/U>dUXb$]&ÞmB,h~05mX$RTU=|uuO^??ͧEgoGJ)nꔫ㐰2 6 KK0HyxtZ)*iG;!Rp/J9.P,%9\`qzI.&O! Sc}zyZ1 8؂sOr#.͔& Cw5'ەYMLff] | 8دyd:s׽0AOfSzGzO!}fnA_.63tέR9?91ۺ !FrrMgM#tcQ#V6Uˑ]W9]LCU5&s~g191i0g8gan4JEOk3 zPu9?G$ jkYlNMC]RSA;XH(ݴuߔjIQ=A]:bl8!s+1-MuYnioy(();cЈ/3J;òd' ߍ]κv=솆[򅑱or9P~yE}fgOk†x+|-Vd$V3VEw4Ro 7[ X]*Ya/xضم~8 : xi1$ͧۏۏao?d7g:f|÷ >e0?[:z=Ec:P? ?t. 1'.P >u 9 b IF;kWӜ~k̚PH$gx!GwsPZvm2c'%]U0|%^(UX݇ y9pfx̦@6NtxEVAKCB56GI= -R"ْ[1и76Em:fZr>:9P^4%745{%8w)hq-Ba%YNn%̵CU>UYbXKiY,@(-ŮL,hqpTWHtmzOT>Q.+0ѝ?<jYE} T}8ALIel_'TIt*͹ՙ8SE_.Ɉ)elvn )_(;0݌[QD?FI&0Py6K+?zDDyvk*M2A~}(NҡOv樯/oH1R "vH${)&djBvE9=VQn_oӝtWOE[E`TƫÔQ6K~:ԌnHie^-`OkQn$QŬ) aԤL',-^?xZ205KgLoZcDC踃 'i rCI'~ۉi6~z^,>JϲH6t G}%DˎYK34St6YCnrG6I弗p(~'##tqNaң B4~:_Z8S$Ǹ $JDl,{mxV̖t#|nù0b;Vg{kc7*렑+}o丵+=쾜d㖮;Δߝ*yG(9t_PV` 8qׇJ?ReaN1Pr,*^ \A5\O\C&Z=; >I^kk)RR\.B-Iz3tU_oo}/a_kGz.ZJT'EkUC;9tTr겏>{P?l[.*+-QP1i]ɱ}zg|bme 0bjcir4ZW.w?'8^A᭣7WO^w_"d96_Gx+VUV  דdžlS'$# ##4'́MMt/F)Kd2T6X7``*rɛ%S6wAZlih>{v)= 2a"b2z}R0+M[-;]PG4وut?࿖?JZ}~B% s@̒b۴7M"8k4ķuhX#."eo0ɉ*m-O]l{ypahs&ynp> kuKvM5˗3kgK <:.a'r|Mt=5hU?ulꙶz]Mؔ՛i#ǜ}g{YHB;2k!:v %_.ѼG6H0cAEd@]wlZ&| .; `:xX[Bl_ 9,ZZu"j Z00k`iUf Œ;=vD\:<`EXBv׆>?G{Z>z{)ЊƆ]K#!r343 %G&R,ll+i d9SRso(Q'-3zC_OdF+K _ɦ_`4θ~fb̮< d$ 0<3I4e&I^i!wfΞ(B4{Pv&Ҍɿ_0JCW mL{;%&0,$q{+/u c=BhCEpf3΀?6ݶ“hmj-m'5~6T]DK%<&bt2o\t6˅7O| #veSS1?M@?׹}~KS±\Hт qD< >n4"B΃Oob^%ݱtdRe1t E FU‚{{,y!a uj5x$%nד,pU89߈>saS["y7CX aQ̪F>76Pd (<_锨 c)]wD4囥?@sɧ r <=M,?-gΰ3a׼Ѱdǯ,vb]åY_$(&1J"ggFuPuoQ"lַ(@gA5Ƈ8=-aK*dltϣFX£1s{Dg)'%kRyN@K. [1CYc[zXTG~CDHR)ʜ0|"Ζ{"h4( {0uSǎ-i):By̏Ga/E_l48k%SO%?A3eظeErE7O-|_f4/$\ Z&+qU=|ApQ wO>Dq,|á9ށyx8ʉ8JʻܡTF|cFGvdkp1ƶ)(Y׆'Iз[X̣^ŧ "\պAy{dYf#9WVe?h6 4uDL*6tWPbq+ NLE "yp¢qJUiOZ?C:x4JRlhʂu 4z$"1T^?qT zI\YxdU h߉PQN+4ѓ0EP\!z(%T%TaeXFW*~D5Yy_-󿐭sOc\PR/ȥ2JeQ f&^Y {_tA87X8T׳-aHgjISP߂^#Α0*&,ا枊aRʓy17 >(~GJ56ls*o6TXi,1)H LNh l~l` 8k|sir:PE6PE L0i:-K̟2^.14?\/,R=5zA jI(L$AP?J^,}vY&s`W7 sHics( *ȺGQ#iQLڔy852̌/HfdƳlN `\=~;ZROo8~ʰE$-VoM%%֠Ih콐8bq&ayզm_y&-ֽvn-*Q#~uO$m1TtVגQ5?^$ ğ$MìL;grͤ^;0j1B,Q9*ץ`8 P P'7N#Z6mS۰G>v'W7 Y#^B yS8CVUDbߥCbNCmO/uqedQծ<:L:J(&:53gTOhL E[h!As+^1DSTx/ںozCUpPR1~me]]ziFm[7`\>I?&!jcp,&qp#tЏoԘ7jlqpA\Gm6@~n4餡hN\DΣHjj.z'AV%M-j`2?mC*Tfmu~\tc ̑"MS{G`nh7M~`qbԤ-M[IM)). ˟A5Bf1IOƆ[t~FzF՞Iu}\]שVelvi[ah˲ X{=, `}gҿ[=+YZ<wJ|2odK:G| ,^iSLJZzBRR⋼imHSmw\I.T|a'fS)ߧl XR5ŏm͡k5h#292L}]'R6"U<1XO4߽ T0"psYmA[7tyb|̶|C#p`,P3sߚ!& 6"m~7Q36a>Vn}z3y i"QP yyU#G8TTO 7^?"M/"R9絖8,?lhCP9.psv"p$/ms֗i{;t$-wzӌc$i$3Vbܵ%B"(h')a6o͊΃} NRM8EUPpj=iR.N#n&½[eU`npXtp^cGhteH*R8M =N Rod?qvD_=Ȱr<;^;zH} {)'󼘗IW+LD^)54TPoQcܭ_lSY{ٽ;Q@FRxŌ2Rw jw^kȡV =P%'Zyy$'"ݏdx/)3L)U,?<ϲg~Ls,.4%֛'K|| Trlieh͵OVY?=d/қ;VX^!penG{ 厱z@Wf Y&x1iOl8 g?g Cb^&l-؜i *L!(Q`GK.MZh8#-RLfFz^.J S.] }f۱y&hcQB7gFgSXhuX=v&٩DEIv1 &ezP, 5$8.ӘܔkP4ߎY Q6m<&!+B^-b.h͹)*gƶ dM$C~H^tNg|PѴ3+ξtozڋQ<`Ȳ@K"xB@y!X)JHȞ5an*9 +@u(SGDzX wy%vЯ(k>x tA*ԇ[8j(췹pqa0!iPSA>(H K\BNSxa1P9fy(jT\͵6nq%|$-Plb:\ck Qp5p0%6L87IVM/B f({:f@ p'8Q6xܼ8JVu,|8ePepa-tbeSZ ךj4QסښN'x?Pab45usj 7WCu*fULu>&g59"Ul~\#J.H &|=j 02n43? z"kE&C [Z!S4fCM?Ar! uhX'5OZ:7N3ރ7Z+ePl-2@ /HPYǛDۘ*{}+;{fdۏf; `/Y\xe1 ׸:a݈2T,,v^F,wDzf%_:˒,lZo HqmA .Dh lXg%7)M&~gk7f%ZUcAtszB,]1_;PnDbДA82#Jo C/b"da cwGS B|{CvW`|-tO1Aק3DQCUAT:3"ʟuɴ8Ƨ[' fԸ^ẘJցk@k$%\:~h"ĈȞQɱmrSUW'kS+$4Z!@b.S$lT"_aOPYͧ>.{j>Ae5%} _u9M$O'V:a[3Bj)5.֫S6-bO?1x6*0/v4վQ΃" O8_Dkli% TFW0++^ x!{uq)z)Xw”m- L9ӋX"?9LK]N,iybY ܒEýc3Gș=ȺpO{ d9ǃ[dACiTU鍫o!7Ne%s0 `.|]D%3Y̕K+ټyYo~ِnܜ))?q"M"~6TkQka[YjэqSy {n瀽svB٩$Sk\WӢ? gY%vr4G9s)'wG\CS0dPYdqMTB*z^5y2T@1+4F$)5;i?5S-$S3#M 8CTh^kw=vOs>m) +h~m"_m9}٬ctynlLE o'V;ىzr|gxD.=wߖ]-,l'TdJIЖQQb/bW|Z| k8_BHjzebݮ잘<LShVت=R ڕvI,'N,{d97e6IeaM@q>iB f/$5Fe{i7}ވMrꋴRyY0YG0xcC@#J1;ġdNɬu 1ό_xBm( U֮ni_<~u|Yc:Û'o޷}ǏG_/^?9Oꏷ?}Dӗ=1-?D c&Fxܑ҃3P#͡!Da5IJ5"qxr~ohtej=8+.w7TgNTxjdw{K;n}n=Dg;z"և8%u=*(<#9U_\Ukk/,=u&KkKXӧ5}Va5?K OV`S;M \]oɲ|VM-ȀѬ@0\85 {VTg~ #É3sDt>iƼO'&?)>#A Ǐ\ª6TL/i`>rJ`M.[ {D XuwIm# 6'5wE{pjlf$~U8ZtB&d}0+;kaU,-a~?pa4)+BxӨn7oyMa#W$c9+:o?*B\`}y>t-n)uM$ ۗdmr/gRpd{nÏ<{ORv9cs4pCz峽AT5mT[bEʂcLGrV:Ts|׌'M٩^nI: ^A.H[qj!H'  T>UHRK ⪜d׎.-${='IYx|ʚit2$B[ɌtSG$j>''ITB&2!3 >8b^6"TZw7UGΦ_Övw{n=B7E*kAKI ~1 ѐHq:BWa/6;:v's{آX‘9Qwu]"e準 iGVխɩQۄp5, rv I1P*d &%7oiaN oYT̪̖rn5J7ժ_C @J{"'`0?!S_ m\fQlUvu.x?_?xpMAEVKӼErSM;b˶vd;DN|N}ҷiCȰi%+Ju{l vV&"{$}o!/Ix<5pdp{~u[ Ѻp~ s%fӽzmy;̿*pll1$Kϳ|?1Dy1iZzXZAԔɽ>z=>WH \L54닕Jj:ݯEP(r]W\߀Ms]Ȉ>4KѕX=Y0aD˟w{ɞzBɲ4+\3KczCk{GTBSkĤblQ+ /rӜYϹЧ>DZ*|.L)ZX !y%*4~dRh8_tکp V`H2G O?ހMHTI hʆf^3Ajx+(SAQ0X:hS?O|-yȯv0X1xVl0R5m<9@K>YgvC$O,p4 "bz<JNOD2%t OLv e<ϧYBò\Cп|lg)H{бQz a+g faa!+ xLaC qx2jYRCԂt^r(ju-qBȓ7 qPXjJ'ad{(T9{a{ Vbbg<bqhC[zhpG&Y:{rjcATF~ /?3>j r@ehG(0x}$8MiX&E!*^#(2S?c #4tfH?"p~{pGx%Ab6ugl֒UF`\0$0hߏUȐ!Łp'GCc0'Ϧ(¨=h9JbG,RHK m}oK`!1'Y ƿVudYȇAR%A"T b\BwР9*4&\)!/M=m$0򥼜 K[XJ{Ab~0}dp7pwHW n?K403=2< < N\׶,ldĺ$ns(rn^-chr 墵[{:FolZ_94 a=W*~ᥑ@a?4sC.F"ͯ@80Rtj#;9SS渟- ߨ̮AT|zɭdb b ŠqOR(P.;12zB3""Qacv#2D37f&LgըIOlO5 y"T%kv] De$F5zm"rK>VF]O!@Y``؃q1+8A,RnyɈ.RICObهЙ2y<)A(ub<FQ.Y܊\k%Ù4xG 8\ErѴEf"҉{d v+e5{d88S&&E϶288Ȫ.o_w6aE5/LEtxOMᛔ-~ݮhwTSő9@t'#Tk|{.~m 16xj@sÄe 'mG]-mK4y23 +् } [oD WX?N)A>Ef+dj%";^ᑻQcKwvǔI"0'Б G[3<x5n^`l|L3v_|WyCUAgi~!6#{; |wm6yXۮɅsyEd`p<ƒCklaYK0B ?KUk榳ޛǛ]Tcr(^LZO_J ;ݼJ{h͉@>G邞Д ?21+UĬwa@ ֛tbq>&8ytZL!xgD2(p$ 3 kS&;Ni:Ij$$_O눭9c|O~3SRIR \f *`t.s6%5tIEurx e?3FHxҌKYt,831.ZKREvYWڪ 7ѧ>{C^W-5X>nYl`hDoȉ8~wlŖO2?6yYWe$eeu1Ja"ofQ%ϲ4B&VR^F;eө>s˝.mKY\N!d?d؈dl+AxO:!bД)nA+kMs$Oiyۉh / KrfPOŎVvBp4o-dpС]ܲc~{Y"0՞6鐎Vz6*Kh:5qHlNZ- RcfZJDs RRH:fBe#DiM‡uvz;^+nrҶ(kHCՑ2PS/᢫FkZUu'p 'Þ*QVܕ\Х%{JCH;ʎr| x\*kBf^fUQޠ0LMCFc+89: r\L^/`lrv $vad.#6M/ N As4RPBI xh}CvN,3>.z۫&y9+F|6T1{7wGS'O;w{Bx= Ju l9<| +0im”|kY^Dlb\pK,! FA^6*>I>ʼnٚ"pa*NF]F sR;r*+P mQӬpiI(~(Woh.L͛0w{8MI۷iO7qÑ|bwV! >*&-zQa5Z_7e2 ̫D` /]BLK;)nP,^e#D8wkm~JDl,ةt3t qe4r+9Ec1@h6%;KZSG6䵍s6SF#0kKEaW (_s(a%8(,n/9.h\\){5q GՈ>VF;e}gPřbv1rv_WP0Z,pOj|mX#}a\iqFtB-vs{,$d MHH !&i*^5֦qa3QKDmMG~@q׉s5RUG W)6} Hu},z CfI̽b@:U:{PYeາZUlx(P z(k,Оc{6j{V1 g&g&g#̳Q7*`O*rXtDք)<:>{Q]O];+-6#7+aEݣG m+)  GQUJQ&$jiDXAzfy6= :r:Tջ}6q ܔ' CG7n7@F 1PlL|TUS3 ?ZȢߍ)Z{Vo`쒢"ڛ#'݊eZ3׉@R]5ۧS1J[rcay~}QJV:󇃻Owowi, rOgW umw 3ӡЋ62R@O\?Qs`%կt8~|,懧e1@tGʺyd-WΝ]].$O cU(jAQg:ԡiʯ<\;Kza*b UX!#^wcN: 11 1ʪۆ)?5_2xu!{ VW&ZN`¼<2,f&t|6#pG0^:H4 LS~ b!vvf dn'&4Ҝl 5B#"ݍ]Z 4p(~IEGHز3$sCSg04uW،~He)zbʧYQt/;32=Z=ٲjf՘ d1c%E DAAfݩvr 2$2d bI35?uٙʊɓtvoA'(~LFL&92pvGNR؋bEγ=V_M?W&Wf^Wcr\.ȯʸw"b,Y0=ec@Wn;h PGr. %^?M>n*y͉^67>\k[4efA>|bUsc趃I4m:ߵq"UI65%^s͹K S|^ePT`F3rtVԍ&.GʇO b!gfxS):$b> \2/.゠`2#ib1Afo& .;+>*Lvi gr|mHfv($b牕ͬ!#90:㗏rd&`\Zоv6[%"C "^Q~orS5䥜)f9:7xZWM_MkՄ5јO_ʴrfdvs~󦙱w߰hF沙ߤXXC} B n`  ǪZ5ec~ge>pЮ]q_Caoi<&jt! ujcDQ^{T"W T·a @Q?YMCrV359'Ɛܵ؝uw?67\s_XARؼY]_aA"">l:rFĩLLVL6*s҄8e prDu^L~/(N~9x%j8V[. Q+Qm>(}}EꌭL Y !x0] ֫ax-#" Rb-18 7_? /iP|m]Hss?xgqyolw>Y7`o+`iCQiXDoc*"2C"FWE\yU=K39c1K ݝ ~ppxl VRaB$6v."80^ER73%GOF(RУOb~ljsDyWfOu/zel|=SR\u}U#U&[ae|D[p`dfvggGHSEsTl|Mz51Hz9Z''=C_-#sIg(#{@1'4ʅ=d9Dy}/S>]bbmǂ0__1V-Bh$qHcy!0$00(|~[׾􀠤8{ӷ꺸1ra\gGGT6 ,z7ulq^V1֔SVa/4_o  [Nӹw>Y1x eMSw ;9uv64oîS3WXwl=$kGC%_ OB ]АߡRS%%S[Uқi@hcs2C!Hfc-\-Ww` 0;&cf)醤9\g, Ci?C7R6y3n@vJF+C?_qBCBoj][~l6#?Y"X>&ꇑ kt1O_g]ޚÂ]> XX)>SOה8Gˆ@F 5NakǞZhPnn(pI &^>Q3MQv%Z گk\&y6Q~XÏPV ONi2ML(qe6nlbׂz[g^O";W\[ݺ˹*KЁquRAa{eGtGЂ" [ywK3""DbsA~lm޶TozcB)Wv4(4Z FmYO [ql- nMJa^B[.9bZ~'O/WE41a`MAͅQ~'t`[{6L{.i3ܻ\;\\m _cn;@kBP Z[`ǘtq90Ja>oÌl'ߊ3Vճzw =JL% nעP-tλD#!Qs$J B LMOE gRjo DBlu2=c 7=ܜڏQ1mLۅF6KLJvQ:g졞 J̡$THUi5ۿf_]{L\| 1@>GoDnts*KwKK  I<\X(u5JV_ &!4Ҵ*Cך|!Qv./$iMpTy.Ϯ^hC8+| H'UYlhkD_G"ץSZ,1 xrJZ}0{_s w(]j<֝*\KB JVgf5S+m Lo}ia2Tj&Z {?%U86 m%؇T6 q啻kbN?xXoVe)ݟUj)I1]cʸSpZe'l~ypZ2{p@Wy(urI:s#EQ8V|<ϓ*=:Ocv<\?Sm/eGva޻(30_6A2IH-fN&Ll1l4fO0\2H(rQܶyn veYIq/fܼu'H^)VDbb&Fq7gG6jD?$~v.%4~I1kxεQ+z̦^&OtFH-'I d4"ͽXd<݋{z.qOuE;(ByTQUHFi͚#]J@=?ݟXZ<^0s&E;NM(ђl޸u50B#$Ί">@9eM\Lٞ/<-mmځElؐ Y/6|ꟺ zp漞xJ:w|# KMSW&We-kS "*tDW$rN5xXGt,"B\qo:Gg`EitqyYRfQXlF-<[to<s-O^,7?pC?C 37dK$` .Usw(@#n Gq ]{9 A~"3揅I3K*{ϲ"&xB޽:J):[Q: D&I(=ۥ҂c"PM+D9' JlԠIՄF-ҦS~rSПMp}̾-1Т\7~:DB nMB:Js3FP)ǭQ5gOpA,LEgs{B}>,ETB8(DƱ9uq=΋ed8H]rz?:-7QՑ #7C̴hm @*%A1`E _ep5b3@/'ΝekIY`J[: h&0KV.Hɾ-ɞi1cG)%*IH w&ܮji˼p2{Kr"0p0V·W; AL\bL>[IIO\7-RڛQD˥#i; *?8g oͬB´#}e1Bӊ9waD%Cc|XnIW>'j8z_[[N9ֿqן bvgp  k?.CcE&'=W^7-褳o;{a ͲI&_Z/X1It<{7sL֠0x17Ͳ~,V\!l#L1Vhյ9:CCL`"IRtn֛q~H5&zkJ(7@s|L 3 @&uzW_t7ދ9?_'go=/. -_yޣUqi"6>-0 D^/-#O}{rUG7fkMm:Rhtk[ۇ,80"X:'[;6hM'%Mi4\^@l 4 /A`֙e osgiL:/#[vO4]{fȴ,,vgˉ\-ZsI\ǷVUciX0]VJSrm5g"P;?!*x'0w$6;RO)O} /$΢8rٹLS̋iɗaF(B(x#7YGqf2&d*NLCL=6á1 0OޘloAFL^i)%"wZ,X/d8Z511# {Һ}~\m*UQ{J1;I9PS? ^[8\|qm ȪE"x"=hύXsf۔*Aq߹JC"!-pe`w^pME^\y##rG|!X.bbMT zV36'{7l?&3|EOs`6OZOH#]WsjHer\8gb5~6+in \w^=PÕ+UnsɃ!ÅUg\pN-VؕKCIYI}D.km.Vrat[N!jל2t#!VۘPŹʩ$(˾y3(QSd",nY6!%Q7?*`/\ܔkVr,0z1A,YK ^*鵭W4XuJ$sB)LNeMUSY.!k8M:V:}@]2@%'ߣ{uj)6aY|yYAPl|1! lm0M!w>;F1YH <>87.:=[HʎPN1Nd/8 ! s샣C \r )XW~>v661 \)po's;DE\*=De/O3}5}Id0c Ğ$0|N{Xf2Ñ %F8$xf2<i )uNr PɀQG"`ٵ $ģS-.fdiDmO© #X"G G@5C$ӗ1DG:KD,gD\߅%ms奊z#8(Jz'W-vC2 (u[4~(UcJaV@wJ4hFg\jA?CY^JynyO+;B]4 n~9 NVN se}niAL $:8Zyc GI'OњW -[6 /$Lϛ~^\4Cұi}ܚ"f+@ٞY-nZ]ɏj8l)´%H-4E6Kfwm=ha V ֞)O8J֮F_{h+pFϝcpT+.(p+[ƜoZ^Q g#t X̒\_2џf(dcLKu5HG#)fr*"+Yrh2-w/_<=|J6AXҟk_B89N)Rc:9HT !<ʶQ,; Ȩ"Rrx]XK\i64j-dT'29z* J3C$;2ʑNDbQ 4IxwD!9³l6C#i #pƏ#zby1qjbۃ KÛÕj.q0p!ׯ1b+oYYN (1ޢ,;30F#ͯ0ڎ,,J!B̢d*_U%wNn5\]*zzMqB1~Gnd ;)Bkɜ?%!lAgh,`Ac8o{E$,UIk6lXيϴH@Oh%)+W(KYtyL=EQa1u6`- ؊EIBCok_nĄZ+ .\e5{ 6C%z۾Ai~Kt"rB3ìnӏtc)Pà ?vIR4{zD5W%0ِԁǑ6c Gwl254&E:K IckH0Wf0%3P4;e9Z ߨ"y@ZՕ/u `pCOJn3i-/41l3᰹yU=*'Gnezxo-RG5D9^!NZ(ŝ]Z( >9♽Rb#6`=V4 5' u)LN5uT#LAbSve9!̜xoA>rtF-Ǚ4!MKe[rhځhXоt R6-([Yv.bEbVp '`|"62ŞH }4d`+~f"=;FYQO/_^GN2=Xb/9edAr/z/Qdo ǯ^W)LYO+W] aqWpP0C' ^-b&1i a91?hSZu;%&[A,jeөhXg'5 5?$LІ#:\5MbФk ]倫l86oAeb]hBxC5 `5T8DŽ mgCޔT1-14YsT (Dd EqaE GVvA] 5ڃo4"w0ܲ\&DR,įabV* *m~QdsepepBEѰCU;]a zYJ~ܧe,]1+QiJj nd^si>RvWI$j'yh17P8F/jrAPNt*kva9q\qz,hn9T7sҬ5(G1y|>Lx؊y:ݻų"ԣߺT<.hroZ99*h[$uN)wI;<+wzŸ'3/ |3>JXxĊnޒI[cQ?;M" d.#rIiM8=ƫ(h*@0 1`پ{ѯ$/H3n.V0y{*7|Qj_jDPOg4W+ZhZ~!sOdg̣WnHPv@S/{!noW g\-Ϫŗh=pwx\U5[@ TS);_UNV1bG@o= vvH5WKYg&5R)^HQK/IYѨ?3dǚ9WN(ILY%駗V"9?'ȧ~Y6.SaorC/ KTTH_09.-Ѣxٳ~B/yt`s{K](w^ZHZJuC>$Q, ̹ڐ >V5&i|~sgkۃoKvrO6X72 t~7DKk٨=Xzvq J2=s-׋7]"UR صQI2 3\| 8'ό\O! GBX7 ԫ$Ut.tR39|w!c`>w1G[Y;7q';$YK뿱w?Naqt>G8 3،/00M^$i/wg"=Lcq+>T^3CqĤGR˻~F+QenNͷwᦋ%7lybEUeVbk@%l:6Ƙ8Y$Hw5TU ֜uNqYfk}@Z;TdV^wY'Nl0z8lSwUӵGPԌ^[9V M FR?$":?ӿ' 1}Д"}8ápBdQ<Î\H TER|d$ I.vTe%>9b#⼇ ytУd)ֈ"ْ1opu|o@'Aj`3f,,<.GfB8;_ {wGrKqa9|àoȕD4z6jw66wv={`z-רEɘf0Cdטc1LfPųLœ7˒ ~uJ(xJemFxX|Bڢ^~N^{myT׸r$v$7H$[>ټuG?=;~ٛ__mgA;۷-Y!~r'*rVq {`AN_I Ƅ M#al5E!~\=1pN<4Jh͠жs88>¾8*H_:2c d5zOdw eM#)s`ۋa|'”3Fnj"0ud R*|Ys$N?Z{ 5dggBI+,;Jbr$: @,$6_R˻Wy۲s |7!V8Ԓjd&N+]bX, ±8:/x9"6FTgoP}YU_| VqzPn ̤k{_]K\ S!]β|Dw? cr]}VksN(UA(@e.tծS({9VwƀmHތR~' c.xgQV΁'y A'Hc|;St H4 +1(BB 7y g&Is'}tg;:MGY h)~Lg% &!0:Nu|MesviH&B"<1 Q!5SitNC oZ40ArzxFi)ؼ!Dw@ 6ZpN7)N Xc.n4E>1 L{ ydڒEIƚ ~g1}qÏbxg.@6~ %_;Цc0]SjEM2y7}PxR_Q0!GlT.v&7%wf]%0igO׽4ur;wO7f<9{Y5^w1ޫџO^iut'7G'/@ӗ"2+Sz;bg{pO㓳1ۍ~>;9|:_#l˓ǯa1\%|z ~EϺϟӈ~k ={4:a'݃=u{u_tԣI֯@ӳ}q/ɫ8W/^i zL?So=Z7jgw ث3`paf2ԿZڜ¿5 F6)*S<|vu< ln { 6MUΣ#Gp3m^ lfSy-M~F-yܥ UUԢ3ʇ1'EL˿IC ^V˽҈C-c>rL5Ƌ6ݨ_`}L8 wM?9c-zD~,aR'ίge;#̭s9| ƬL[P3\S oBn[ע@3k1, x5c(]OEfo8nO,_ &rbb P˵^Pxmx[y4J>BRՠ cdti67|h.ϲzg$G pth6rπq2mWr+lX uV遽U<竵$EQm;ԣoW\5|Vx@o_fג>`S>5t3d15⧿E^/BdKq?8bD:a/t!9j>*8e풽4- O͂'$')}]`\l%떠*w5c .Mf]:[yW!I<#MPQ^AYo 9b_TP.ikD`,]%*hdp993[9I\{eszB+@Zqv[^WP`G  ut)96.Qx׼#oQ y9Ez]c~ӎ#~l=hE9==z_N{iDSPgGT*q9q kԈrUhDa^ޑg> -gSCSp'bV@E밀1R´^ȡl hY5~e@ݿ1E#vN9das$ȭrMɯ8/G52r~M-4ƭ´Q л Et ^C, KÑޔ#Xr[0⸤e0Gv":xrP*4 k˹UQ_4lG]? Iى'gxGbO:8N#星Ol)6q:DmT.>x+B<@l s$xX=p`SrHb=h ĄK@Sl~ 2{e4GmI5^A=$aq#V0ꔺA'T$D);eݙ_QƾأG@ʠ}XnCyD BF0qu'FC?Q2c{Hdv$C4жRSB 1%RI7ƗI>Ay>% 5$E|iiF}My`ΰ]uHd^0zXFZp0ćLHɐH2Ɔ=Db/\g:EojG|imM%ɕj垎y j\Ö%W'9fWDքJcEN-(Ǥ`SM0S`x8#^ [4,SEМӑpuv-4NA628Q =U#X^9gS>ˁKqK,#]V&*) ^ɚIH salP7)xp jo0˵7@vy@L=6Q.Ҵ 2c ߟ+»5BX;hM[ߎW}U[Ȟl2:|YR&XÜψHQ{o¢FnDάm?W"61^Bp'6T$J2L+Llʿ?'uBk( $;Rt,ԼMA]m^}c:\GXg mBo FpR2]e?qQv3;Z&D |ɭ?ʘlRaxPwfu#,,ף1ϖ~i.q?;- Q>`_T8|$KdU0#֎wW}6* < АpYh])%`ޏs|!S"DX*k/vllLUV0+u9h>k@!z ^kG? Q#?`™R\"[0q{{+P =izp=z![9N't6[36@( ;RԚӧ|Q Fm>hoN!6ؐc/mULH)>:IAQ74-9lYT \]sݺoD[[%޵5UL۴Nؗ|upa*C- GgE%a^룆 wvZ;mz!kmhgpǍZcnFͽ4ntnwz{79J7wn稵ÍZ67j[vi{;]ylFݣw}ttǛG[[mnqu#6vaۛCFvxoˍ[{Cijon2¶7ZۇGnxh{v[G[h`i2䛇{#hkl흝NG6zG A &;괎vyݭV`k@mluwAgowpg=<8h[;:a6[C8 z{`]{{-FXgloQ 0ytwd?mlla&`hpu>~C!'dGA'=`:;;]FXK֝mNޕ^|f677vZGG Nw~mz-Aju{T{pzq#٫Nk j6bTnﵶ;Dzw;[;[nk{kBn}èm{{GFF(;0nst=twwz=7ځm2yv{GE y}amvyGǝ-OG탃c}p8>j)̍v:ۛTsFǭ.Lۭ1vڄi.Lx`ۅ)rގÃ.w~p aA:>t[`=PwvNio0*ZЮ#p#f:0*;[=&à ߲Awa[G-ti{pZp^ז$C;8ta;[϶%g4:l-vA #l.϶% Hmovw;6l.϶%XFno!mm2x'9Ƹs7{Mv{`Q>>nl~m yq#X>cTwv6wvd?ذ1Ž[p0*[pp0yl~=ڃ=čv;у#&6ȁǛ{0G;-`b=Ffų6q( kfAhjAF{{;<ۍ0#OQ{ɐx=b" mgsqp,sm1Gn6w:;<[`[=Oha{a`{p1nlv7G-b{ڄ3qèlm~m0\nov[G۰-&Nws' $؂ {]FV"m.s5J2EIZyFC7q oOsTWi|Šw'ܩwny҇{˭聈JbO.8ƨju"cRATi)%xceUI 7 M}ۂom6MߠAߠ=m-umzr v+=V?ߝ}ÆlC_7p°6~7&ߖ}݂,d;vhIpNu9=׽=ěmWMq& 1j9l-ĝqwwO@Y-,V&zNDLjʄK`)F1e!Y&8=vV6\W,2ѷ.if6pԳklZH{f6#{coQܳcm=M3ݾkۡ>[v@_{h.іx'Dֆ6lm-;Nw9|Cvnp |Ct,:>BL&.o׮6?>ڝήE?:KM=ق'sQa?ᑲ/&_=?9÷A*+EWڬ)]**[dD7ɊJ/l%+.ܙSjt5MŸyb{7Lg#y_)oX#0x.ۻ1~.-%kct={?8*oMÆ6$TB!= pc l~\t2,s=P<0 ;H*_:?oQ))ON"W@' vi`6Uz3H 5)V_}%?MB"CS]ZO8?D^K I~OP>p:O\a7:lƶjwb?;_^Gr TMVkkNxpW?4#}SA'T_A҉vctԕsXkcdV_z&K>dS+5e|O`,@4Fb@c~b4"` `7b'ul\do&\b}AFk^{/(.FUivo>Խ:{RcaQb8śu# 5WEc/cv1BӲxЈf8%6TAˠg?Țihk12iQW2ƣWe~?1)Υ:wvAjDy6ptt+0D~#݅"S'^t^߱?YAčC-wؗ%:浝7^P~l,mgqCӾVc ntw4헉)߅w}4t0_BL&y$M-e67z A G&-lDBM`V0òϾIE1D`L 3G8ڨiK{aT4IS) qe KL/,·0bB1PW^#h ϖφm J|C)D}1pRpm'Wy2xmz"!xPP+ '#<9ٳ7hHaly7! #y.ER-s㫦1&3uO4ݜϰ`st?$f<G8B8s̒|vQxHHH@ZB$ C1ߓe[i4sø 6%Z̴bik0=qhda;zAV'vc\GGc 'JCpɽ : 7{7S\tǨdZy>Oa#toN.,oJ="l1Շ .z19Bw=P8qg&7j%TOuS7.M(AzLx[g;ShGb?vq؎KVT(Bo>$ѩ1l<%}m xe?zQ(>N3 {JWmD M֓)O'j$|K={.؅L> .%Eئބ6q6䧫k(;y ĉp#a]DYy",Ey}*e,b+ 0HP QQD rxE膒ХH/yfQ'֐=9`%2a, ԛ fgsȓ cԲPMׁ_J2 1JL؊t1{PΓ mT,@j?ž]0$ M0Wr՞Q+6msa cõTb)+A q8t yW8$0hT"H7 6>3SȊhwHp4HAcmuGD$o˜(nΓd!18KwL>irXQ>KG](y.(:;jD@@!_p9es212 VGez ^rQ@yolȻPˁѭhJl[="ԟpHL*Л8I^ 3=~nH.kVw9yLW`w>un(S^no1RNVK|6ܙ3gD* m}|Y(:.a{[Ե3 '0BؔjctwqK͌IE ͢p.cTRz[͜j)j7IQ٦[doBdb_L4ADS-!D݉n8oP<Y 5t5VF+I@݄k"W1 k}aፓ/m o1ej  h@ 8K*I{%VYԃ:hd"KfZD5yʪG$ۏ3&0|/IfT [Օwl풢-NRQ('rS:!jᔽoOT\/}p3y}wfe}8^]dJGO8akfp=2*ܹ$ Q(/)uraPqsn/T hJzkabu?($甍"yDS5W}lv7.FOy~h@XF&)Wu]?&<֒~G X.y |{( NCZM?Ga6?4՟0AV I!zW;1B(ן ~EERJX`uX5h[)9~G$"`kT-]$F%4n5Ye?(m>piK 6CRArc=ȇQO&;xLIϳ(^ۖ9ƤĚv[FX 8$ hx8bro(u1#=cXjֱ}2A4M6*u)$l}`dOKR uXn#{Z'W6=/Nxg-I:e,faITJ;y{x{~܄JIZ>hD2j ۰P?|}@%OiJA8A$-=L!-` ׺ Ax- ;[{^0cΫv@i=cj^ 19?')k Ia9c xT[L 6^ӿg7"0|o qp%qٺVl(-">D@ym25JxvP+Ni9C lC ,Hh'L#ᄭ %ӵJa0Dk f> /ۋ63v;]$Y&=EVD VZx4ޮȋF,_C]6?)TЙSbӿ7?>]9˶Ul[s;55Yyܺ/+#&+ǁ_eF]rʻ! .oEbLh̟tϪw{FL47 .R׻YSR3o2Mf.7 m5]۽glzQJ%F;0D.\jbqJ! gS{gEX*L9P>yG椇Ým&[>sѹ|ZPߐ *25VIlvO%W&w"k3`.CϬqG @\w6Gіߦhfx%{a/ F#!Q%nMaPM-tp}s6v#npD .pC68n ^A!(b{3hõG\1}z?ĒfV\i ψeZVUјmRGa\:tv#T҈'5Bl ϞۈR@2m#gJϲmo~ّ@F,RI0_[R5)Y&$m%9C\ ^wb+9͖7@TלJaN6z+h2ܻLAXg฾OvR)$A~iInh۩+{s@u& 9v3+O_E䞏%:4s{YP]>,&W0&4EKPB (97-l΅B3W$=! 1n]4ѓG}Խqs7N&c:BavDCf̮4NJ60=!-b0ŝ@YL|tW|O,@)%8bgc}-nU:ր?MUpv5$|Ae6QˏtF#b<6ńC{#7χnɩߖrZʥ≯T*ߴ77K;~\TmP'~JdӦ$ 4ƁOםmHdr~A!st58q)e,ي9kNjJO<6Y掱8!BBn3Fmnz7ƶZ ڇG;o#A ݭncqH S;lވ(Ԝ{VG~"#ZG!ކx $sw}v,ցЇnYdzraX(C2 bd?'e[;;6p1l fl G&};dn4 z8JlBrYE=w1. WS\;:J`h 7 qrNC2F&bdڔQjF'/[O588 /pz֏ܳT5>EgR=?wACJ m:THI *DnF-]{•-GFs϶63)~U {%<5@P\T˧`8ݗ<0yѬKps^nF88a_`MO_y[rnV?m߬Edj&JDv3T,!; WFy2ؔwQ[++"{OIcT/$],()Kp}cϗBn|jcZ(B8 d-%)[έr6\cPaEavع-`9UL>6۵tLa7zQO'f8̡G<`= Ŕ7JP9on6?lZ/ַII1E,M;|#t,C\]?4 9I8f[#?ᑿ”S72PJא5 <?ؼ@Y]ݫP{0"v&X&S&>}_Tůx/$p~wSUP™Zw{[輡\HԸ$h礫DpPj4rvy'-A\ﰻ~p}2=-te; v{m1v sVahKK!u au,4ʭZX q[awr;;q:[7 tjDEf2 ZV b9`=4lO J>۬6PpMMN~skz(oy=t FIMV{4<'Qy?󓃂15Դ9['qi'ѱE1;4Z+1=WHtHJF,gs ֡Ş5:N %B1Y$nn@/~lI^nyEY 20: Ɩk"l8 7֞YyVYNݣעo@]/+iy_yPw.9T;0C-0''Aaf\Xi{OZ͆w]Lvmck8 аY.H-FguLIB-2\Q;!"2b+[ ?H1W.'4T>Oe~0y7Е 'k59 EK9q}{9v_9Ǚk[j+&#^Zu揣hp=Z!2̉p l8-mLzUʳ ؘh~,_'?gV_=l::Ǧ-0Gng(]eBKV\R-GQ 5°6/;g݋$&ApN>+0F{"w6@m [f}P oT>KFcKўIu}˺Z݃q1዆nl}:L@T#u܈^JR/)9+MT<\diƺYQQV- (YȌb)Oǁ `|Un@tnNîy.=Y3j߱Hys7G貣_^s1k\t(y*RXl]t [431|Hl%h+UsLz6@W~|ׇю`q=YnB$9] Cbrz悃ԝľ_"U?! )A#b {Ba+6`^0'fbҫ&1p#hMsĪ5f@J?0zhJ綔ΊY ;e8-Cf&/X8xh9 ؚ#9i Nvv|‰M Rҗ}Ab~o,NZ*2meBy/h<4LYB$*X3_|__F]觓'cA˜j#…Kx?13JRH@h: $}$(:h|~nY nk&q*I#m.y!v& v*[3 舖J ::uZcl2t zRe5Kk-R+oTgHA:QZBR_\'@_YW.[}PSܚ J-^c%|NQ^8w9oi; <>Z~ aizx-&~5LSp}HZxM!^$&i #Óȑ͚RB]1 y"N2K pa"kX<)s7w HvXda5t|X)uyu5C dhsW2Icm)__օ_OON 2j }cs>Ll:91Mテc"^;>Fm-E9# HP1swQ`n 7[w-V* Fĭ=x;~@i,L4}Wu_5Г]DSu"uǜRZ 1x5jw/?+w_ٛ=E^Mwr̩: ] 2_͡Usdyz3Z *`qeT›ZTJ ~`agN"&s!1CSaNbT鮧{w73(k]ue빲/եLڭ"^kޓ+CNT>6rZOSASKL3bVBYx#E?ϓ?|vtYpyŋK՛ӓ?ʹ;}uGh~Zw?_4o{o^ˆ?rKjZoy5ׇ̌fxNǓ Hf/@olJ7(4/ՑٞY8C7 x+i ⇵服P2ɂmX_̅H^6WMcqʙ I5kBZ[6q -,7/EG]A,Ļm#xԪܱ ש/'] e@9Qb#N 沊daAf/Hdn⮚ g$37BLgiWoJh Hn0JGra"E9eY/棋KUK}:6}dSZ1jg †P32Ss{l2'굩O؂|O)b&, ^:Ӎ^qU M0wtXxXgI=6Pu45#|Ljg=UN%.m'K tξSh`n()Vp~@ }FͽAYw 縐/%;,Y[.9s?t{}uЧbmW6ibzÕaaazFްeB,beVZg;ز-喯zpht/"Fcsƪk9%yg}n w`?t\;<:.GmSQg}68#;KO)]jE?DMIbڡZܮ#h!!08|PqkZ8 ĘK1z' m I&b%ˌM<+h2&LX*-e0e(v#]8SlO ^dôvs?%\ RV{ vYi(nXQu|LPJ<Ę>,m*ŀPqlNݮW5nw-5J1 ՆN"1]g(XZf o9,ԜL|Ovd I@m7wwZ)kWLt`W4_H$lHTvP\Č!o8l5!L Q&ziK6Y/-UIˈE{^GRndZm?xաZ ]J$ǁ\38>*F6HCWc 'aV) E9B5~L9w4~F\maނ0VYQ}TM~+.AŖ9:~vC0-m|1Njz$^*dd*Mr˘[Ytd[O/= YXʢre:Y/7VB[Vϲ^k5#;7ַhS IMΓa m":iGjq{B-0j.pu0?c0ʝ`c6ڿLT.S1BPE:rir1g31@ыt(7s vdq}ĊNa 8Ho,ۨINi2)`N Q+#h1KdX{?ƟbWFPZHyf@=eMQ" +)ÊiBFu3av@-B t9scȧŲ I "KOyBţO܃Q>(r7{d[;,XX *Wf" v8Ol~v#A'f.uLhJ'lx5׉˜\=Q | +[Vr%_YXjmw=d~cʙ |mC1>*RX/\}VOD+֞ofl}Sl (\(Qk%ʰ6.گD1,pL,.rAibWlsho#@HtX p[pfp_y>v6-cqnT}gʆFq^ et @R1U+[ΨG$}7/6߼%jp ^~~rz֭c̕?ox?_tlQZCʥcO/ !Pr৲[[z}=ȿ༁oDJT:^%ihp^[ED᱁%rcյHn4"dwQ掞1p+(&M]kG Ȗ&?~AA>܊9H?Mz9^_@w22ؽJPrص[ ԏz.5>fk!R&/N`J vsK!eE :b!"+уotˮf5~љYLgL- UQ5c ,oJq^[ceFQ#jp_FUgN8p%<?¢.`0IAc/2Z6 Ji7P72Cpf/^`>S蚞+}߫ 8Mǎ7~%ii]cDmhөg()?mgmz[_fN(ܸѠxpHa;}'q|EʊcPxv 'v&TmwITrjgdABDk:rab!5sɦMA{;Eb!_Ve҄ɺjᮤ/[MeL~hW_;$PgӳVW?.@$W j_u $H#8$ZwM9E#D[$dPûz S|QwS#4|4Mv.9OYq(P9okty*0]5R4lNm܃(wތ}QqDޫ*64֞HesEI6ݳVZ.bFv 6>ͲC'xUJU:Öali("WL{(f݌$> ^>$S4|\y}6O?` 4 n#/Ă/W8(C)= KC,D` Ol/zh(FҍC,lHIP˦ P ]S몡H(P̻S̄>+ 7h )G18Wvq"}c,yN[u#BZ 1a!t+aTǣcUXĹ0b&t%_""O1,1"szt vלc1zT*k&'҆&p8uڈ sՉD^iP5Rͼ7?3=#C_M䰦Ma٩SICWzRB$"P! -6]|6vEj^6cc}Y1 Λ1!|.oQ<.0><8>;#9lxrc\X6g.UVBrspKfP+9$ھ©`__$ƥrSY;a;;[wlʌ 7OP[N{ ;}Ip~jm]>xփc?NOz|8 tYJX$ >,N^4Ž&,cDƷ@XӑZY7gPu}y:|/T[1~5 #)Xo~} cpuKٿf'|2ML) RܻlNruC~\Ak5cEγm-N^-F榝rDզr@Z;h9E͋!!M~ '}d@iz_CTtu5zlƻԜH3~*`kfogbqjοFq1+4zvP_\~{ yNo!:N!xذً1+%ݭ)7xP LWH&sy'@waaex;}~Tzׅі(0-KϠx{Tq@xS~9Sefjr ߄ zIs&d_QբWԥi >3%{ }Y_q[ޞŇ͉D@1oC+q{s X`:'Yu'b}l *ф/nFA7?0u8aconAP:ߥ"Wvbt3]q!]*tjn1U.3XK<tD/̟ goſqneQU @qtJXTyC%0m,Û;;X @EeaQ`l W:(K+Am"bU`AyȔ |. _bIqe8j|ePHuAq>JŒ0( *qnjI2X~2hyBJ;\\] X^ Kq!2W_B?2h'bɧ7Ǣ<|8G/·C֋ Z;7h5eP{i¡Vǀˢ`-X0hZ:h>T)FCr`9W_R_%Uoձ3V=Ep2Ke*ՠyfp2X*)+X@A Y-`ʮtV(;xK\2}ꮲ0\K|*~^]eˠgDqçϢ0 -iu,ОBAU_R"߫"y:C5~Iy؂bYd͊˒cl m{ZT.Q JVbA=Vh FvJFU|,5Znl5ÝK`v5Ko3oӡˢ,so+wNEuilpݜŗ.mu,,*'l~7@hiZow𞡾 o27 XZRϫW*e2Ll=Yb x )JgkWu%w,(k KhuwūSg\X*{ õc"oK*`moWO0U +T=_RWx, ZLb'PsqK* a0|b-{zRKu v(ACut/iV eyY(Pk}Cizw:wB1) T [! |H> 208 Jp;zwg+V ;T 1]_YI"ۼԞ-C0%c(by2XS3V-:e/ub c;W'R_%ePʮ.D͕ٿUH^4,D ¦ezܢlH9@:VBuflb4޷;n:6畢K:S_'~^~Шrl.3u%ViQ]ZcDɗ+ie },*JCe“_R{@V4|tONϥ 32;ZbzKjB=Ӧu>Q*\~lUOiFu*nA8V/ax0/jϒr]0[{z s)^1w>BXWE`%\+&cr>* t \ 9/[pg . w9Čv_(`^թ:/2+~:ʵx(nP bSQ%t"2w{+ވQU(,U-+gU[3]VFZey%w =$B-`W*L<j?@,ۦ^2P}HKȬXgh#+I<*m KH+Q?9+ T*t)/U)-GHEQZa\2Zi@Fv #Vk('P/zsgo(oN |/纫OEUb8+V En;OˇursY/Fhne*ǨfQ:<>UUԿ܄;(4\A]9/T+Rځ,UCs·x#ʬp!!T/37op!T%SVΚ05P֦ ǥ$~KX;j "9a oSYAB0twKATВE7-X%wRXДf`j/I~*̥`^,x/n΁?O?HRp^,K4hV*hѠX4m)_\EA+z8,?głS)8-t[,xaG{4 S)Y]ESj*%J_ѱqͣ[TZK^"f _%ҴT`7is+񊭲p,**%NrM m%ԬJï.부JSɧJՕ Ӑz连\%x }]R]hxJ{X] s'OFv)P'^0 yl‡p%|WfO)ȭdd6oOB[KEdk#|iyYwi, J+Q6GagT-W L\TUQ[+?I &)f뿲֮YYsڽGTۗΥۗǣMgR3lFǜL$pFSD4l] $ᨭu_b? C\ËY7z}{r; 38,]Bc g3a򿵷[;bVoo&scrBs_Ny9&R6]\:GU6jƔ;srA~-'xio̿&f|% 'h[ҀT 8[G{OLX<͇JBn),Z,;iCai}ҙEn@i%ƕI 6;>_\\t휲Q"Ai6njE|NҤ/\I Qܤqt b؟(Q~ܠ9i+![<bU`ŰgGJ \WfLubJ@D!T=%.~CZ G3ςvS fZ'0@'*s8#<_DP4qJXQC) ,9j?Q9ob_,::}FCg5=7< 1g[7s 9,KJϒ) {RJEU^,-#QOf%#L (;g)bAui8R2B6ux@.5@JfIV.̶Fp1&#X-ƙ8+X^ jyFRl-K(2p8'S*}p.i`NJa :i лǘ{[:@ RYg\mmw$}X~ ?=AWi@:G2:u@%FCb&6Dp<`1Wp%42f _1a:KJ* ^'c>9y"C&8OAڙz7}7n8ٜ F/If@}4HM2̇d c*D6 PG>?0Q8s"wCp'uSc%@ Q j҈|?f$,B4Z‡@x[_aG} /$̓7ZYY;֠>F`hDɸ"c#Ej=TdPAvWnjDDr害P ud /W "}6ʻvi@2ѨW=*igYMU0;E6&nNHr,:ESg RToQ=ŝee yj|m+baa3}qЌV!FCӳ )jLeR 1Ǘ9aY`qMvh4牑X($eHIQ'A`; 8͙Z]SP7 /QZ5L6r dRvO&C,%iYX{#>`x"toE¿f=:@~r<W_s86ݖFѫD")J3M`D4[5J@(}df…A6Ǘ7 #qc_^azaY3V$hDn4O(B0:?OFo{?^T4]4P*ǑvKTZ(Czoql\ΔC8XdsPr17jkNa=.f'azAOG.,C2 7 .IbO9|ei'8pO&ώRdݪjx>ˠ.+#Bozp+b^YEC|)!@<ǤC~#j{6~l'jHgl4Ez]ߌL b|5:ncT/ A,Hm7t:>[ܿ0Xu9 =24_bq!rtQ|/@hѦ')\:{О^ O>uq6V~h''ː['Aq@~9`- nx}R껩7A9$ _$DZH.0pqւ$+z"{ʼ)5>dbddQ|˙̧pmH;'Nӱyߙ;aq'/(;LطxMR(JT_󶕫ތf1)sfVRX:^ ֱbZ":.R.)EgxR]ec< o)(tj|k@>iL8깅e)HTg]Ag)*ΐ1; ( Q|)?LHSᬹ{GwG +9mt&Q+;>KSG2(i yAFTP鍕8l(X5 ~}3hG# ; R~ݶި9Fhhnp_c;=H ^'ɏL /YD!`]`zUmas_ +X|O$cVͩ/Uk^/HCE k-AJp^Bژ.,+v´ksfo:v.mp..@{.GnHߍdoA!-kxDNjDdYXfb#!P,>C?ٿUjX9qYs1)'G6$wᘔV?%X"IuB gnnXcF_XhwVߩ+sO o_<I t(ZTR|1om_@)O?CS˳Sl;>=;{  DoIG44<t6EڣGY--\Rc[ػ"&H(yΪ__uϚ!IiGϘ(It/~f_*qWBMSOqgM/;5D#$" j6ÅF}#+eXG"`wؚrpmQ[X Ah5|wb?P۰I3s%o2N|s "$m5j|ɀsVؚR5MHs)렲 Ol[pS,gvo>[ Ȇf8bb͗_4fm`LK 7}~hQ0Z)sy\zAXxflHi3bٷF_Pklտqtʀ='E!{(a|MrF@d3[ZP"]3mʸNCq|Ք:x[P3WΪ%Tk-_ky!e-f.W5/,6X{b;\h0<|?ײjy%6% jmo vd8\GigfNldQhie܆(,^m-.#^La<D*qV!N>^F"Y4+fQC91ŗ ~ k!CD0܏ @Gd>K5z͞}<;ޛotZ-p殦64TELV=2B^r/%7ݬyߤP/?N 6?7#Ӿ{ za6rbիtC4'F8P>!zy6I@"C;cb6͚I7k`*gJFV4*9gTx#P1 Qn+}٣75w%ܧYk3 f$i6ˑG$YG5,Ho=V 6d,h|fl uct=@~c]ô^ 3qF~?X;kofFd to5r2j6v*7%@F|fy}C7$] Tu}LQ7LF?!Ch_ PP&.!jF0liMoWdvim̜@94(/9p>HğgѝU.ŕk@l}(u cBBj]"?1[10Fd`T &nWuŽ 0X _04.2cp-Il-J % q| D@C~]f=ZF{W2*zs+ܘZh>p3Gkđ?jtQ䐎Xfm#yC@h(1꺆id ftwA89sYY6sw8l1ӴQ<˒"}拞uDJ(*X۳9hX֜ .aZl6"Bypn=A[۠ ?Jɻfe VTؙƫۖ֊4t(Xu_.Y,~i׾RhEG<`>a__Xhh fh(6xLEjAx. I=,;/_SgFiz t/2/$>πs~NG:c01ݘo?+qtw=I+$YW΋edu mehRa0 .){opn46ŷk-M˯qJhvC>yCpސMEr]G#`07qIB0"NWf l,o2l'w:Rl ;xy$X_s9-a鵽QP夋Wi??A!dWi`1Ҹ ȭW3B6.GA'c+t3 aDٞa0qj:DM{َoJHV y~~%'3MO3%>5CY.di03s$M2!c8_屇屇{h,)"@38A5_I`MTmzLy+_pXնZS|k8u3ހ 2V h |Nyz aZz@r{xw 5,5lѡ~cVXZSP+)r XkpJZkt+ nrRsJ5lk*âEE]l.ٛ\ *Pu;B[jb$49S]C d ~(teD sVm~$m\rMk sQFn7eTv1FO)1'yqa9Om9x;!jj(K1y;Lj)F6GH5VT"b@ N