/* 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: * Movement/collision utility functions, * as used by function in p_map.c. * BLOCKMAP Iterator functions, * and some PIT_* functions to use for iteration. * *-----------------------------------------------------------------------------*/ #include "doomstat.h" #include "m_bbox.h" #include "r_main.h" #include "p_maputl.h" #include "p_map.h" #include "p_setup.h" #include "rockmacros.h" // // P_AproxDistance // Gives an estimation of distance (not exact) // fixed_t CONSTFUNC P_AproxDistance(fixed_t dx, fixed_t dy) { dx = D_abs(dx); dy = D_abs(dy); if (dx < dy) return dx+dy-(dx>>1); return dx+dy-(dy>>1); } // // P_PointOnLineSide // Returns 0 or 1 // // killough 5/3/98: reformatted, cleaned up int CONSTFUNC P_PointOnLineSide(fixed_t x, fixed_t y, const line_t *line) { return !line->dx ? x <= line->v1->x ? line->dy > 0 : line->dy < 0 : !line->dy ? y <= line->v1->y ? line->dx < 0 : line->dx > 0 : FixedMul(y-line->v1->y, line->dx>>FRACBITS) >= FixedMul(line->dy>>FRACBITS, x-line->v1->x); } // // P_BoxOnLineSide // Considers the line to be infinite // Returns side 0 or 1, -1 if box crosses the line. // // killough 5/3/98: reformatted, cleaned up int CONSTFUNC P_BoxOnLineSide(const fixed_t *tmbox, const line_t *ld) { switch (ld->slopetype) { int p; default: // shut up compiler warnings -- killough case ST_HORIZONTAL: return (tmbox[BOXBOTTOM] > ld->v1->y) == (p = tmbox[BOXTOP] > ld->v1->y) ? p ^ (ld->dx < 0) : -1; case ST_VERTICAL: return (tmbox[BOXLEFT] < ld->v1->x) == (p = tmbox[BOXRIGHT] < ld->v1->x) ? p ^ (ld->dy < 0) : -1; case ST_POSITIVE: return P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld) == (p = P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXTOP], ld)) ? p : -1; case ST_NEGATIVE: return (P_PointOnLineSide(tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld)) == (p = P_PointOnLineSide(tmbox[BOXRIGHT], tmbox[BOXTOP], ld)) ? p : -1; } } // // P_PointOnDivlineSide // Returns 0 or 1. // // killough 5/3/98: reformatted, cleaned up int CONSTFUNC P_PointOnDivlineSide(fixed_t x, fixed_t y, const divline_t *line) { return !line->dx ? x <= line->x ? line->dy > 0 : line->dy < 0 : !line->dy ? y <= line->y ? line->dx < 0 : line->dx > 0 : (line->dy^line->dx^(x -= line->x)^(y -= line->y)) < 0 ? (line->dy^x) < 0 : FixedMul(y>>8, line->dx>>8) >= FixedMul(line->dy>>8, x>>8); } // // P_MakeDivline // void P_MakeDivline(const line_t *li, divline_t *dl) { dl->x = li->v1->x; dl->y = li->v1->y; dl->dx = li->dx; dl->dy = li->dy; } // // P_InterceptVector // Returns the fractional intercept point // along the first divline. // This is only called by the addthings // and addlines traversers. // // killough 5/3/98: reformatted, cleaned up fixed_t CONSTFUNC P_InterceptVector(const divline_t *v2, const divline_t *v1) { fixed_t den = FixedMul(v1->dy>>8, v2->dx) - FixedMul(v1->dx>>8, v2->dy); return den ? FixedDiv((FixedMul((v1->x-v2->x)>>8, v1->dy) + FixedMul((v2->y-v1->y)>>8, v1->dx)), den) : 0; } // // P_LineOpening // Sets opentop and openbottom to the window // through a two sided line. // OPTIMIZE: keep this precalculated // fixed_t opentop; fixed_t openbottom; fixed_t openrange; fixed_t lowfloor; // moved front and back outside P-LineOpening and changed // phares 3/7/98 // them to these so we can pick up the new friction value // in PIT_CheckLine() sector_t *openfrontsector; // made global // phares sector_t *openbacksector; // made global void P_LineOpening(const line_t *linedef) { if (linedef->sidenum[1] == -1) // single sided line { openrange = 0; return; } openfrontsector = linedef->frontsector; openbacksector = linedef->backsector; if (openfrontsector->ceilingheight < openbacksector->ceilingheight) opentop = openfrontsector->ceilingheight; else opentop = openbacksector->ceilingheight; if (openfrontsector->floorheight > openbacksector->floorheight) { openbottom = openfrontsector->floorheight; lowfloor = openbacksector->floorheight; } else { openbottom = openbacksector->floorheight; lowfloor = openfrontsector->floorheight; } openrange = opentop - openbottom; } // // THING POSITION SETTING // // // P_UnsetThingPosition // Unlinks a thing from block map and sectors. // On each position change, BLOCKMAP and other // lookups maintaining lists ot things inside // these structures need to be updated. // void P_UnsetThingPosition (mobj_t *thing) { if (!(thing->flags & MF_NOSECTOR)) { /* invisible things don't need to be in sector list * unlink from subsector * * killough 8/11/98: simpler scheme using pointers-to-pointers for prev * pointers, allows head node pointers to be treated like everything else */ mobj_t **sprev = thing->sprev; mobj_t *snext = thing->snext; if ((*sprev = snext)) // unlink from sector list snext->sprev = sprev; // phares 3/14/98 // // Save the sector list pointed to by touching_sectorlist. // In P_SetThingPosition, we'll keep any nodes that represent // sectors the Thing still touches. We'll add new ones then, and // delete any nodes for sectors the Thing has vacated. Then we'll // put it back into touching_sectorlist. It's done this way to // avoid a lot of deleting/creating for nodes, when most of the // time you just get back what you deleted anyway. // // If this Thing is being removed entirely, then the calling // routine will clear out the nodes in sector_list. sector_list = thing->touching_sectorlist; thing->touching_sectorlist = NULL; //to be restored by P_SetThingPosition } if (!(thing->flags & MF_NOBLOCKMAP)) { /* inert things don't need to be in blockmap * * killough 8/11/98: simpler scheme using pointers-to-pointers for prev * pointers, allows head node pointers to be treated like everything else * * Also more robust, since it doesn't depend on current position for * unlinking. Old method required computing head node based on position * at time of unlinking, assuming it was the same position as during * linking. */ mobj_t *bnext, **bprev = thing->bprev; if (bprev && (*bprev = bnext = thing->bnext)) // unlink from block map bnext->bprev = bprev; } } // // P_SetThingPosition // Links a thing into both a block and a subsector // based on it's x y. // Sets thing->subsector properly // // killough 5/3/98: reformatted, cleaned up void P_SetThingPosition(mobj_t *thing) { // link into subsector subsector_t *ss = thing->subsector = R_PointInSubsector(thing->x, thing->y); if (!(thing->flags & MF_NOSECTOR)) { // invisible things don't go into the sector links // killough 8/11/98: simpler scheme using pointer-to-pointer prev // pointers, allows head nodes to be treated like everything else mobj_t **link = &ss->sector->thinglist; mobj_t *snext = *link; if ((thing->snext = snext)) snext->sprev = &thing->snext; thing->sprev = link; *link = thing; // phares 3/16/98 // // If sector_list isn't NULL, it has a collection of sector // nodes that were just removed from this Thing. // Collect the sectors the object will live in by looking at // the existing sector_list and adding new nodes and deleting // obsolete ones. // When a node is deleted, its sector links (the links starting // at sector_t->touching_thinglist) are broken. When a node is // added, new sector links are created. P_CreateSecNodeList(thing,thing->x,thing->y); thing->touching_sectorlist = sector_list; // Attach to Thing's mobj_t sector_list = NULL; // clear for next time } // link into blockmap if (!(thing->flags & MF_NOBLOCKMAP)) { // inert things don't need to be in blockmap int blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT; int blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT; if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky < bmapheight) { // killough 8/11/98: simpler scheme using pointer-to-pointer prev // pointers, allows head nodes to be treated like everything else mobj_t **link = &blocklinks[blocky*bmapwidth+blockx]; mobj_t *bnext = *link; if ((thing->bnext = bnext)) bnext->bprev = &thing->bnext; thing->bprev = link; *link = thing; } else // thing is off the map thing->bnext = NULL, thing->bprev = NULL; } } // killough 3/15/98: // // A fast function for testing intersections between things and linedefs. boolean CONSTFUNC ThingIsOnLine(const mobj_t *t, const line_t *l) { int dx = l->dx >> FRACBITS; // Linedef vector int dy = l->dy >> FRACBITS; int a = (l->v1->x >> FRACBITS) - (t->x >> FRACBITS); // Thing-->v1 vector int b = (l->v1->y >> FRACBITS) - (t->y >> FRACBITS); int r = t->radius >> FRACBITS; // Thing radius // First make sure bounding boxes of linedef and thing intersect. // Leads to quick rejection using only shifts and adds/subs/compares. if (D_abs(a*2+dx)-D_abs(dx) > r*2 || D_abs(b*2+dy)-D_abs(dy) > r*2) return 0; // Next, make sure that at least one thing crosshair intersects linedef's // extension. Requires only 3-4 multiplications, the rest adds/subs/ // shifts/xors (writing the steps out this way leads to better codegen). a *= dy; b *= dx; a -= b; b = dx + dy; b *= r; if (((a-b)^(a+b)) < 0) return 1; dy -= dx; dy *= r; b = a+dy; a -= dy; return (a^b) < 0; } // // BLOCK MAP ITERATORS // For each line/thing in the given mapblock, // call the passed PIT_* function. // If the function returns false, // exit with false without checking anything else. // // // P_BlockLinesIterator // The validcount flags are used to avoid checking lines // that are marked in multiple mapblocks, // so increment validcount before the first call // to P_BlockLinesIterator, then make one or more calls // to it. // // killough 5/3/98: reformatted, cleaned up boolean P_BlockLinesIterator(int x, int y, boolean func(line_t*)) { int offset; const long *list; // killough 3/1/98: for removal of blockmap limit if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight) return true; offset = y*bmapwidth+x; offset = *(blockmap+offset); list = blockmaplump+offset; // original was reading // phares // delmiting 0 as linedef 0 // phares // killough 1/31/98: for compatibility we need to use the old method. // Most demos go out of sync, and maybe other problems happen, if we // don't consider linedef 0. For safety this should be qualified. if (!demo_compatibility) // killough 2/22/98: demo_compatibility check list++; // skip 0 starting delimiter // phares for ( ; *list != -1 ; list++) // phares { line_t *ld = &lines[*list]; if (ld->validcount == validcount) continue; // line has already been checked ld->validcount = validcount; if (!func(ld)) return false; } return true; // everything was checked } // // P_BlockThingsIterator // // killough 5/3/98: reformatted, cleaned up boolean P_BlockThingsIterator(int x, int y, boolean func(mobj_t*)) { mobj_t *mobj; if (!(x<0 || y<0 || x>=bmapwidth || y>=bmapheight)) for (mobj = blocklinks[y*bmapwidth+x]; mobj; mobj = mobj->bnext) if (!func(mobj)) return false; return true; } // // INTERCEPT ROUTINES // // 1/11/98 killough: Intercept limit removed static intercept_t *intercepts, *intercept_p; // Check for limit and double size if necessary -- killough static void check_intercept(void) { static size_t num_intercepts; size_t offset = intercept_p - intercepts; if (offset >= num_intercepts) { num_intercepts = num_intercepts ? num_intercepts*2 : 128; intercepts = realloc(intercepts, sizeof(*intercepts)*num_intercepts); intercept_p = intercepts + offset; } } divline_t trace; // PIT_AddLineIntercepts. // Looks for lines in the given block // that intercept the given trace // to add to the intercepts list. // // A line is crossed if its endpoints // are on opposite sides of the trace. // // killough 5/3/98: reformatted, cleaned up boolean PIT_AddLineIntercepts(line_t *ld) { int s1; int s2; fixed_t frac; divline_t dl; // avoid precision problems with two routines if (trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16 || trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16) { s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace); s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace); } else { s1 = P_PointOnLineSide (trace.x, trace.y, ld); s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld); } if (s1 == s2) return true; // line isn't crossed // hit the line P_MakeDivline(ld, &dl); frac = P_InterceptVector(&trace, &dl); if (frac < 0) return true; // behind source check_intercept(); // killough intercept_p->frac = frac; intercept_p->isaline = true; intercept_p->d.line = ld; intercept_p++; return true; // continue } // // PIT_AddThingIntercepts // // killough 5/3/98: reformatted, cleaned up boolean PIT_AddThingIntercepts(mobj_t *thing) { fixed_t x1, y1; fixed_t x2, y2; int s1, s2; divline_t dl; fixed_t frac; // check a corner to corner crossection for hit if ((trace.dx ^ trace.dy) > 0) { x1 = thing->x - thing->radius; y1 = thing->y + thing->radius; x2 = thing->x + thing->radius; y2 = thing->y - thing->radius; } else { x1 = thing->x - thing->radius; y1 = thing->y - thing->radius; x2 = thing->x + thing->radius; y2 = thing->y + thing->radius; } s1 = P_PointOnDivlineSide (x1, y1, &trace); s2 = P_PointOnDivlineSide (x2, y2, &trace); if (s1 == s2) return true; // line isn't crossed dl.x = x1; dl.y = y1; dl.dx = x2-x1; dl.dy = y2-y1; frac = P_InterceptVector (&trace, &dl); if (frac < 0) return true; // behind source check_intercept(); // killough intercept_p->frac = frac; intercept_p->isaline = false; intercept_p->d.thing = thing; intercept_p++; return true; // keep going } // // P_TraverseIntercepts // Returns true if the traverser function returns true // for all lines. // // killough 5/3/98: reformatted, cleaned up boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac) { intercept_t *in = NULL; int count = intercept_p - intercepts; while (count--) { fixed_t dist = INT_MAX; intercept_t *scan; for (scan = intercepts; scan < intercept_p; scan++) if (scan->frac < dist) dist = (in=scan)->frac; if (dist > maxfrac) return true; // checked everything in range if (!func(in)) return false; // don't bother going farther in->frac = INT_MAX; } return true; // everything was traversed } // // P_PathTraverse // Traces a line from x1,y1 to x2,y2, // calling the traverser function for each. // Returns true if the traverser function returns true // for all lines. // // killough 5/3/98: reformatted, cleaned up boolean P_PathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, boolean trav(intercept_t *)) { fixed_t xt1, yt1; fixed_t xt2, yt2; fixed_t xstep, ystep; fixed_t partial; fixed_t xintercept, yintercept; int mapx, mapy; int mapxstep, mapystep; int count; validcount++; intercept_p = intercepts; if (!((x1-bmaporgx)&(MAPBLOCKSIZE-1))) x1 += FRACUNIT; // don't side exactly on a line if (!((y1-bmaporgy)&(MAPBLOCKSIZE-1))) y1 += FRACUNIT; // don't side exactly on a line trace.x = x1; trace.y = y1; trace.dx = x2 - x1; trace.dy = y2 - y1; x1 -= bmaporgx; y1 -= bmaporgy; xt1 = x1>>MAPBLOCKSHIFT; yt1 = y1>>MAPBLOCKSHIFT; x2 -= bmaporgx; y2 -= bmaporgy; xt2 = x2>>MAPBLOCKSHIFT; yt2 = y2>>MAPBLOCKSHIFT; if (xt2 > xt1) { mapxstep = 1; partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1)); ystep = FixedDiv (y2-y1,D_abs(x2-x1)); } else if (xt2 < xt1) { mapxstep = -1; partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1); ystep = FixedDiv (y2-y1,D_abs(x2-x1)); } else { mapxstep = 0; partial = FRACUNIT; ystep = 256*FRACUNIT; } yintercept = (y1>>MAPBTOFRAC) + FixedMul(partial, ystep); if (yt2 > yt1) { mapystep = 1; partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1)); xstep = FixedDiv (x2-x1,D_abs(y2-y1)); } else if (yt2 < yt1) { mapystep = -1; partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1); xstep = FixedDiv (x2-x1,D_abs(y2-y1)); } else { mapystep = 0; partial = FRACUNIT; xstep = 256*FRACUNIT; } xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep); // Step through map blocks. // Count is present to prevent a round off error // from skipping the break. mapx = xt1; mapy = yt1; for (count = 0; count < 64; count++) { if (flags & PT_ADDLINES) if (!P_BlockLinesIterator(mapx, mapy,PIT_AddLineIntercepts)) return false; // early out if (flags & PT_ADDTHINGS) if (!P_BlockThingsIterator(mapx, mapy,PIT_AddThingIntercepts)) return false; // early out if (mapx == xt2 && mapy == yt2) break; if ((yintercept >> FRACBITS) == mapy) { yintercept += ystep; mapx += mapxstep; } else if ((xintercept >> FRACBITS) == mapx) { xintercept += xstep; mapy += mapystep; } } // go through the sorted list return P_TraverseIntercepts(trav, FRACUNIT); } ܍_7B^ߝ XUvu/遱EEjPu6X+qNBIǚǷ}4_||xPWuk`J,Gi,$؄vFfH~Lue6ƾ7DYgQa`CkA2U7@=h'aPbhwk%nߚ=rJR(q:a}{1eT1X v;Kv]ј%ݽ?Z=8KO}TфyɱP~gסoÒl5-`+>gf^š:4H1P]c"TJ2JzՁT7sXl6ECJ5w=JBwyJ΋"`GHLh.5+L>Io}r4Ӑ@VuyMr84T,?g:O6([OE(dž ~yb_JIäTMoF!5 ¾\bm*K`@9f.j!:TAx##RU ?u5fMڵ9X6rI9QqE|9QPśtS0$6s(&ݵ bYݴ2߽Pkw[(TI̵s6\+ةUOR =GM;ؽoM{=OmmpZ,uqN~(\yޏ2Oqףэ9g* 6x;W6]j{.ڝ)L ԕ"4 pO,PVA8Rp+`=$jBVDvMsUE)PtqHI$& |1~d `:O W'S`#S,0',T-_~"w?Xwv.҆|q"{xn WU6ivE 6B,Y3]K1!l:! >pR2hSsxvPk<"'bkޅҹ8omEx {C5ufA @5exUg2m.| ~8}$5_ɑf='nTc ߳x3JV g_eD(obH|uUۥ=6,["Yń9sE?I C UV /k#&Վlj5HUC҆;F<`S(S &: krdot *c<8As a„|X=5ݕ23brI0V啸ZG$eu`IF~Ϫ^G$\\%z6g<1D8AөSd&UÑr<㾽'-n|Z<6@%j]:@%]>1_S7HJsJTZmec'LQN@*w$U5͠g,ţ+0$iS t%Q?0Ev`V*Awv\U R#1wt ϶/lsRXD6 EP;QMo'U$qxNTkrŎB,l4g_QImڛw]ֱz;S[}k0gٗWԮM?g]ͥ7$>XT|TTmxۣ1'WwB34Q۔ fd9\ݴyvD@U;,w/rDJyL^?5?H䨀d$ J:?gѠ^;/A~dA+*rěSwne6DvvpeȎC-zFnW5+Q3iMі/> MWX?VYP8W'}R?smZdl~D/|Qb;H0q V\Q姌[D P'ő! JӘ4Nj!J!zgr+%Q^HmHz%!0-3A""%R 0P{"JΨ;~@=ߢ3*Yv0,1{Pn׶ݘC SDS($rP ׵mFbHg6h /7[ \wWZggC錊&ʭnwW6 ɥ't;euY x⿾usS dcd" )0PI#k.}KhD'DRx'_i 'Jgӫ A[I?cSuyf r^Ab "hf,=TL+ E,(Ct? wܷG0fnZ;R|W۴vcKBa`'@dH>SdQگqXh_]($YѬk%J╍jyBXY2.|̯DKZj&=M34k}=ȴݽl9f]cnI>|S!\Z*XojIŹ6S7#0"y&¹eDƍ(^[5F]ƥv CrG4GC>RCFGszN B_pγ+i׆ ] B̍hjǖq1R UJ$`tKyژk}Z*5ѣcLM}f]Ze+q!B(qc r\668 rp9:J۱խ]K{7P)Ҏ6ڜj'_euqpڶ[{nǭ)%, W6o! ,:Y,zfߩ&&޾n{yB=\#mm+`7MR-ʅrQ's$W>@_hPU:#EhPCt(6UbtPq.P!.cntXLqb Qen dK'6Iq'81gG)7k0FZS3š\iR^ ȟ]mJ'tK|26KK-򻦒 ߹8@Ѫ= u익^pߢOaF@F=gdP_R^=6˦Rلy{nNLݣ 2 1a~+e8ぶh YӔ'B|KlUVpove A "·?QxR;B +s̜xj4}V &d03+eYuG D8mV1stH*D#(w/+1%B%+c~b›I~zGRU%48! O\FI;Z9W.W%TQ:x%Y".I(7"O:ҧW{bxLixzY1ԕ&_^(H7PfBe}c[yGx a oc p66e NC- FUG:հeOjqyٟǺٔK<))A["]dģdˏb Bm8\4Dn\5N'iRﱃݕOX ʡW>^Ot l u'h xpIuMl++(Y쨀 pF`)S6I[KT ,.?hBZ6%K#idƵд?e qE ΀ҺbIPNk1̷/1^ixKSSfc`z/ZuRk7RV6Mnin뫫kςKYYW0˃;cG94fA(4Dg"1 8OOuPZ`4xJX:]+r#pc$*ٗCVP‡[|o`7ũ ֢)⥶wMD]́}(8Qdt"f縋ArXV2>S8URŤr&MEJO5;tZ^Uk[("٪;j1Z5KAyb a[Iz2cA~ȏ Od \>\s v@Ӽ͠<+|,4E 29UťيZe{ '1pz -J‚3cLppbZWwnDٵ@4P߯3"sK t3% l:7YEɿDga&N)vduH!)p@سܰYc#A쾣!ӏ+)U ^9,IxNٴd8KRP=KW6AӸoY+\vO zU0y'lpx |::k͡Fy @w=5ت]uSɽT i (zf2PPt q*e17rdfu3٥ݶCǏURIjR(_ ^9P8;2SO4Iݟlۣ50]a|,0]$Qc4 dJY$qPjE6L`\FmNn]V+Kۆ}9A ':3|i8Aw7I44[ɨv,QL,EJwhn u ߱dBgK|Y!`j 'a so>'.=Ҟa]!O:y j~a;g񛆓xnPd@O}"A06"&.,s*B?dō}phVmfF?7$=쟀wԋ4(BPT_O) EtZ^?C \qI+p8~G.] zur/oSLi%dQRW{e jeîEvV/b /wunhtfP>\#L:in=X+ÿqwF=+kmIt 2:ݮ4? /dlH;qڛJ~6\@IW_Wb+Z#kZ U`Y-8j*)dB] ^DIRc{@D`!BEgAwǡKȰ@x.gQn4uSn<&\]˳Eiȸ[T@| 롂OSi9RƎw7==aVkk|R,:|"O&zm/ RS>@ LcbD#\@f(Θ*݂ j6g(̤D/a}X#NV Bgefqdó,2znG(_N!&R"z5 <*(иUC/4+"b*Dq¦M4&JKgwo1l+ÀF~`0 `e$Y-C|g>[ ]n~(d2ČB{EǓPw@hHw JW<"id-+ԗ:z =\BO{HB,@_[::b&nh)},pTi5A0o eL֌#OzτJֳWxYIJ:;|6ԃμ7XHzx Ĕ0yC6 wr-Ccq@ uIڗ+rfr(0q=ڹ ^;{Dym{0`g;jHA5~HUA~%,1!*%s1 Ävwu;QFm:Y =5QLخ./TzeA7Y2Bcb%X-> X #0;2%.-CdNOw@7Ԓ ._-LK(=$Sc:BJ7yKnS{ۡ #W'N*$` 5a}{9n2  Rl>wA͛d% usRjh2i"37^p~BP5#!x{.KZhoaBOy!r}&j8]A]4(!7Y|lJ {Եǯ 'OGn jj)r!\TKB3VGiのd'ƫL,l ¸tTxzJY~'Y%=R)j,(Rkn/t]Q.ƘjKt bf+KTN-F1ld5X#}䦘s]s?qbQ^pa^Hݣ&Z ?Rz'cA|p|T [Z [eCZjH]Mi8Ű]D%/9,TT`_|s2qSR<_DdgҨg+hY*kF 'LiؙD\mHȇVH4 Y1[i_nW6W%xĠ [P'=z/x?u\5)VwG&?Y)BJC$ 3$Z/A>! б1X=^ #$PZ[̒x,qJS3L&Et_qz|҇3 Mym yh2]0[jӇ8ѫ, ңC[6b5+UO%_IoJ_ݏfhB0HE/r88_ 2S Z& n" ggl8R3cz&ef};EG3@*Qy[9-)&y`)~*EFjVuҵ[o+=v')2m⏍+u E(B83ߧ@eo.Ճ[qd8wK0&~Q8C\͌B"~e)!ִ\Ip76l4I ~{>7Ȕ*7;E͘VGCOTa'>z:sHxkF^Ѥ3Gp.0z+pL(6;8@vDཛ`"86gˁ+]ZQ%~A_xb4`4+| qG,6f*чu P:jo.]Bg yY_Je.{r@P"*xO켉:z =+ !OvsͨCJw2։Bfj}Rv0(qJh/ 9wcZWy,oY0MiY]fw_Q&M^@h1/U7NV1[?uWLl9$^%D+ÑQ!w~6 tiA1':ɥ1t,ä| :n?SyVQlP` ۤb[D/x]7 oK u:zayfpv~kdccmc^<@#p}Y䒁h ֑s@ӂ2RjCMLDਠysb'k"6`WKI nL~C,XVSЙb;A߬!V['+S($4fā8oz|VH`>z:uX4ΐDX& +!c.Rvt9Ӌ*(]]i; ;^*"( ;di/e!,2pi(;u*ߋBmwT6:RU;Cϗfc(Sbrէ;u?f%{P?Q$ ¦[r׸CZH^sTbzS]99e2P*!~?>'nS*γ\Mh7^^_;"_S 21 u*Pf1ָu) :rGf9BH/;,NC<Ր7rk^8KR(_W1% ("p ]k&(by 7K\G+3NP.EaRD+9@#8Ҫupf7Aa}ʤMb xQO.}aRȿ.z~ $Ю+iZ¼{^}r:~H4S;<&_ab@bʊ4awɪOS[osKrkF#Tyi$-$5h96s_$!"x1͟Y= rrI)M6یkD5{CB|Cگ_ǦҟGulocm\6ͩyqE@їX_X[j9tQ5If LlӇ~sȁY{&^z^Չqlq[}a!< D\,߬7K^;pPiƬs곣>BfDЃ;]pb!ѺA/xE쫖6l!JUG3g 90facAֲ0wwMЏf|[KXiG8%"'`ǐ&*tH@_j!*R R {RλFieO}dqRെ\g* 33cs.%NG%x/1q "=ѽl-nYnyvKuCa8 k2C07_cnjkCۤaᕜ J2o׭*D} 1N[ţ Uu OLhz26͝H3$>QSqzl:WfPϷaMĸ sھs֣VRvXqxi!?6\-ίz1N {"^6\gc8q. @Cv1[4<&A2:>p-z6K0&UJbq5GylUrJ$ެb-7Ox6_4~'A͛R~>5*A41#3e5G\ $/=kT_ }ߕzuXf0,Z;H8?+tM~!\wê6U8-6I16<`e I[9/z/m0 _8ڞyF^qS C$Gt+&#6cUp,7v.?%@P_!i8Q`lD<ZVuhͥkAI{1lT|P4@`M丐/g)=hAi7,y#+ꀒ<02(( jtKύ]y܃͟u ӫ_V&#NPjze C (A}U擬M_D ]u2$$~ z#<5wtiϞp`Ū'ʷ,HzmB6 t{AD:Yg;_w=t I+LOMEV+ _K m~[z/iX8sT#\"\}T׃\!wZ,1'Sm{鋍 QArE%V߬`':){rp;OPtW}.pmGJ&] )!eví%wy[Z-n^Yf߿= /  >>Z^mBz{11/Kr2@+Ӻmҷ2zymF*4@gZ3ă0gPTP>LX! RtDu x]^v怤Q-Gts Ґ r@3K+a%?`f]]fQXܾ (uh!{ĝzCi2~ i!Z-a|I="od$|g@5A*q\`-M~ B9b%y)gwXJ MZ 4f^t VGq 꺆iP,=J#hg\6E"wzrnʱ)kiKKJ_(E/ bH[ mv1IN' zwf~B dU|*8OQMjA!bZ(@J0OvQvN Ήj2 YX߫JxuNq itci4]2&uRmжہT[~r&^E빯og1St!ߘJaWTB9C?fF5 Vh&Tt AG^zVףڠr؀g |,umKIqԒ1ͺ\J*OQ*w 󖥗5:FGvq2{sĪU_\+Zp{<9'hOϠ1+DQnH{W-*tf3rZ$8!q1V3:6\sf5C{u]s c!>jUOq kb$3@£;h㢧+ 7[oB$8@N*۱:JL;;k5avQc \ȼPoN~QY_b9gMݒ!(]FCO^ޛiJ:єةϨ֩l$=adA&nciBAx5\ϐJCrb [:`$(eFj*HͥS<CMUfx xNbs]1:%'Fz٤%HS!A-|Q1 OQȢ I|zܽx1_,﫜mbTܫjH=,i3OEߘɌU&+w~N5k?[4hz~VH;JhU] Ś4P49UXrO5hh۝5p }a0ήVpЌZwXV.uqD9ExIʈz`Ǒ >^USfj4+Wgu^:b6ou2C']߳cs5ۓ)BY%:(=s070J]ʟTćXDp[/p}n#U6>slݞ#Ym^( E3W#5z(,,3_ B0>kc *c/ǝGTPI'z6"U(N\h*K4`//(Wm0ɤ].!{ a\8mclj{ʼ:_Jdu wV!IQUogSuF$kG@ٔrsɮ; O֓hW7ro<$UgMq8?8E0'vo9dSư"T-;0K>\|'s&^҈,ԏyJ#Y7,:k|.2B]X=̈IR``Yuf*g{sPСn-&<+R(o" ф^" [$V=t =.[ƶQ> *Gϰ$Kܚ lmҸdZ*C\qmu[2'ތ̜[uc웼' 0(? Ѵ~l0ڜf)V6 =O=deAGVݤL$@~ wPvQDzrNH':Ҿ=]\i ڒODb -Gm7׹:7>+%η_cBr_ڀBG$c*q)I[E3-왙{˥IfϜb\xklQH5MJ*.WjcX ;*Ol9"m2VO/>TR,@~BK[ɕJskXa?Ԏ YaRɜ[q}~cYLh5]Ȉ qǵ\pXzˣ\L ̖R9Yė Y=p8B+BZ7qcK)xV.P'Fhkm 4E싘_ gm(Kir8d詃?1gˢR JvQczI!dбF@cSȷY6Ա0*X/"zK H=ɅC"-\~ùZ+R;7aDp^P쵰t(\,=-GYQED"NJL}9iґlH0ݬ ÿ>` Z.%DZ~Lc=QN)VQqbCc; ԩ5\nCCM$C_QQy+:2z YhdR{D&.2n6g@ &~ZwWޫ8SO$2v 䣀 hC@c))Bvtкx"/oREc"K݄\ۙ4>1ur6([cف84n0}J$/zoY64u6#Mf2`6 ۴h,f\tڧ@"W3"lPӍ>N|S:cN#*}mͥN^BMM>䢋dgN)灕Ͷ H|nJt$+FU <C$IQ'C] (b/?LN fmO xd@3KQQe(Ň?W\uSdmqz5[7 j!+tj5PI4jsuUDʉp ]ۑR, EJ$9.0qzDwBIcJC-kzqփ1=s"K } 4He| KܺO=Y@ P f 50iV E.Vq 9|1r,iA"Ԟc-6T̑B\|j1YriI/LU#Q ^%#a{0B%)tAFq;ig`wKv C+^b_Z\`#߅h|i=sg:%='[?i6iRO*'Ug\7%uJ9D^;kӪ?̷Crϝ{)m?ȶa7XWCi;j8U07{͎vj4lr蛙Kc_0_\HżjDp:2Z.2e`rmI/-_WP6Z\^.I)AfiΉz ͟yZի@9*9 BIiD9B.mzN>椣)q[^Rmݕ΂$~eȵ*Xo!?]*e_G21uZ|PƦּ 1^tOX9T}>i#g=C:}#ⰥJ?쭌Go(r0b!Œ0C7C602ɟ 8Q[a (bm?bojzE]Hae_#Zup0Y}X R =8n2;'Ml!S5bע&2\m |?j::w$kHWƙNa=DW4koݨ0fT1 F}}򴚸U h"wr3sP 3F[jke3dg0p=[֎Q+.aog6o\~c[ %yN!]vpfMuk7/%$ll ;hD,%ԏW z?skö@.ٳgum2G*-Hq~϶ ptl.1 1Pܐ$6E.w\)iqdpZIy^&gvJs0儉"K'Fy49H#4 QPy>.d)yL@LnR!晻EItiy[Y%"Ä\E3P>(֢ \~/SA6deG.9/Hy}?'# S@235yV&@,~_njHQKև$n t;hYC(})%{?͹'syJ*iMY@zrO ;bbVzxl\Hy~V銻qwyM$ͨD:] 30ڴenX оp{$+G'U)3!ぴ%4s7(Le M:ӼU T ėpRFE}g)DVWXZxg:3]hͭe߹_DG<= ~9/0ӑ7c ޠp<_ 9sK IEE4LODDPSs;!dmfG]SrFri~B1=>$^' $J-,zEjH_\؎Qdlp{!aOT!'B~f`RCtWۯy)ICHFO)$(L@KQ&YX&NAq z^mhyXڱlo=KSf bjeY ʅ74i<є'UW; _zx=CWcۀ̫~ҝ0TB߯žc%ݮla_:SbX0.DR*I .@@M\hFL.^XpMU(YZM@]VQ3ߤЁʕȈЙ;$ͩiQ%"Hw쬡@l&zb /| 'Ȳ؈-ef"_n-aî߽f3OɷZ>7p7u9<,vsJ60'mƢ6;Aa_<{|@Xg5.1ŻD(+>~b*dh4u)חeqD@?.uXcdkt0^9:~E0]s^UQ.ip/BKnmQ|3C4i9{ s-ʶez*+T^LȡDS7bBBgއ=y~[l,Կ]!oW褺{ 0MvMuJK3S_.YCTanQz%U&mhμך z=\ 0Sj|9ʘn]Wy,LX~A%Ȇ% ;xU(RrԾ ID>h}z(eNz1.Hfݹ 1oefRk8?0fTr2,Sސ]*B~!.%VXs']M,K2H R]JgМ/]YSvñcb>pT~%Uc{5BuZiADm- $ ^~}!/ +;/HTT #gp#k y;:7C:'t zt{eJgI*L&j!^fDIg[6>uDŷ9ūӳ3,k%Y+EzE҄Y`%TR͈0qFp}!`5_Rf>͸ "KDzp\&t-J2/R$ğLFڈd@?U0 em \8zla::wg\3# A5D-.(hD-&v-ڧPr*ꏁi\v@Wy }PzYV#Җ  8,((w0.F/EgrVd1n$TsI9p/mV`,l3I}Ai}*-=/>4"0hG|]x4i)iNr  v z0UdA 8OO0Z0_b#!W\꽆D/ I yEQ 5iM(fQJŊQ[{;C樶(7TA@ 1bR {$ ҵ(P;؏8Vj6J'0FT&^)¸~r$*Dgm />[4hZ kݟo-e۹͟X[Nb{]<Ȣ{cǻ;+_:xj]4  .yG'gyawN)ȼN)Ã;hJLUkI=HZCɂk`(h*O\U޾Z?*ΣTۅ"X Fp\@EKEvo ;S1K3%R  &uzXc 9a? ye892A(jX2ZȯMN4mh,,۽Hu 9:[9"-0I>EFB[uR'?=EqT)Fmf.i5Vr&Pf-2YIߜ^wġ:|%XQQV+1Sl D␋uwyoo|J6M:K1 bnH#Gt-{7fph}E=hoC_T! y}OhPu>c8-tEah;դI;0mgo~3@4#T|/a #L .ј3Mo>QrH/R1\H3ڝfp9Nn?FzRc5$$M8jZC&(gΙK뜔nɥD_4s1D9JhCM-M{x ymw8] ъ ]5;[騞R<}0Pda;2ßUW7ɩn}xQCz;l${,w:G=˜>^B6|o)C04 DXb6%|5IȿJ`H*:үGҊ*spYmjwjTOE_Si[ۄP j5J|TוF[`ǤBWPٰ"ɾ\_{n,C$9?φc9&[(y}[qðg2>!Q2g8)N}sw l|ݍWVcz˯U OFy;_ [+6$c[PQyvFIRFITsF(\_-jt4{J32V- Kj'WWx{<;m!I̽1wNh*W}<K|[>mb(4 ٙ{Ie`NXŰ03QIqvu\VL i|V?*㵉W5 OC'=hn'ϗ}RRI]$DM46B@71+UMұ}}=CL6W09Bv\,$ S# @n}XZu\Tc$BSJuY?k?+ iFG2eFW;:ك ^A> bhm&/"9zLѭlՌ.9iEB݊fF6)¶Xm]܀'9֝&PW7dK#h %A?KgLË`}۵E?ӌ᛬2&=x}DkWOfX!GXxM PGZd.H`pg@@<BHDc<~m J)Q;c0]`Rp;QxFgP4*M*5ڍ0sy&F6XF"vۀ~ipHύw=Z(@Aei fx!=mpYoUdaƁ-VEwZ7ҋY-R J3@`r56)J/@s/ꖈ\y*"K -ժn/CG7j/x\0)>=<0c-l>WWPVo-v:õ?ޜW3S[/jEP? -ɠ[;#̣ۯ320aų57 Roq//U:x nK?594,_ 5.KDsH1ĵv.?4{9/K #늡D7=/]WMV|$t5 $N)c? WL\Uq%\ij{a4=oՊ[=W +U#_,mBRJVF^Df6dc9xYlɥs|"ve M̢7|A`j_?6"4]~\5dE*_@;דTtoż60;^Q=Jʫ*D.o+-q_驱 xC+#'2!qj-CBsv . <,䀒TB;suj[~ci.[K|I_L)ɄN@ۛݹdAnz^%>|dS- wấ! kH*mjLRJ4eZw&_Cr*EnW-57Z8̵3wK<oY"٬ٴlO6YW|~jG޵0Ktf̗6uH+Wv<~SzC9:Cs%fURgd*\XBjFYxW[V2ЯLV(]nux]e;ϚՋlPU˲Fgzhu2gp0^qۜ "NϖV7|\w`!aތzW2on UQkkjլ b6ÔWq:śq,嗀0O Uf *=]B!ʔjeٮ NϝDF±D-Tڄ$n *"p;L؀ >87}i:yݾ?kA0$̼T D{~*=r1b$zo3W\':L`^k~W s_=wh !䷻3Y8y0^aHdWfz %$jX^*ʧ Q4'ag1d|g!_qoIZti*vM4e;nѲY mϓRx)T7PWpY4\9h#}hUGgړWF\%{tGX`6Kh[~w'Ke NTP[X-Z7/du]~)t`>)pM>W_.g\]7 n۟aQ|wFц(dhS$g\gk]kI)|ý!:̣IoqOd3k\&VCU: A3< @Ts<)\f.۷a{wUj\~]QOe*r%xZ5~}f,?s1~QXw+%|D.bB`^\P%e=6]Br-aX-:-RG;U BU' ݩ3uii4@q 2!1x@_+~ZbYˬ6 {9@-};Ov,wsNmjڇxbhejrB)ᓎ]`B([rDUH?:a4iM/[~zӺ@ZI-vB0oSڠݕ+YF@  &=c̭YD[},EFzHZw U(9ǑlqB`[XO7]njտcĀ/l%`> O*>EJMQ #~~Lk9T^=ɚK4yը!{[{QrO*gb{6^xޡ`Yr[-{XB@0 K3>2t^G'{eu-23738`kg]q i2". MFkvfL4<@vJjī߲^>Sn궻QqCگC,H^"9d#]ˆ HߎK*-d4uNZFWXJ ^8h9' ( tY'=XW,b2?Y3RЯ taKWOxɌ}5w-~g\{}$<}\$=96ڞیi}'hZ7+ĉ|/o?R4 +:pZmTGd-$6̳=`=<)G 1Jrͯ@"ĞF 2}}0f$`邸.kgdN@1c劭D M~Dc%|ȘgG oWtYɫkw0ѭ-zQ5=:$>KN\2 1Ʒi3::1LCdTa͇5` ũ!> )+%}Šg> /]j'jnߙ߃ 'rF9~zC#0S0AOaȐ9VD6E_\E!!={A"j]ٱpo7>/$ զ!Kab86cO9,we[>XO0*Ɠ9ƄR(F;z[$qkVZGz5eb{N#@z;sej5n(]]cV< @rP)\jw!5?)r5sY@(?RZdJhfS.یoh3 E \ mUKXzy0ק XUaE- D(UdjGr'3< Aun3fvd^ʣ$lՙi֣x`tC$ԭ8%%v. (֕J2| xE3_ n:N?nFwXHQoMzf>Òk.r8Gzzmٝ7 w9e*0}d>?į,ut;ݪRb)"M/ʬ^u)k7zr.G-S!!_cؼ[k,=+Q mJ~oOJJt,nqrnܣ+2d;L+Bg H@/C~r쫊7gg.V{+6^~ Wf!3~%3ƘeNgKګ7S5`[6|׃Vo/Rfh|RD&XLծ7m\@&]|;av nfyov|[Fw<C4_8^؂$i?0`8YWWDGceZǃs'Y|2z'œ]ROr~W|L07;-$Ӳ2tFP LȃSVX4 rӉ7{c-+-. $8V=N~t  2`W4?!D4X5\׼#/b]UmO:ϫv떭uF0JE08^^ &[s[:Qg(BiAV8} 3U3`&#Ql8/Dhrizbػd{ kh82RDļxIxa|']'LY9Eπe H!zAX~17kBAQp̪%eZe@D}ʙ[ OJ@IQ r3׋M?HL+*̂et$ހ3BBXg q_§qץrE/ߙ-ّh C\c c&WrY8"DD -V]K v6 ޅ-=j{LiyYis8j>0#YC[Kd`6mޙ|5-M'ȀF^kQ!ue^Sҟ( Үv60\>&!/7ʆT^ JpnBZ/kX'_<-ސdž<(6L$ c.':wS OQS'u>),r}ѴDgj[ΘS!>\ @|9%Mo/N`BgjG 5^޹ {Mtin.F'Q^ڈ:yZrl/s:ZZ.ΓPe&eh0mM6+-#t:ٶ$SA4jB/Nf|] c.0YZ9+Xm#6{m턶 E΅HiEZeB:5}O3t}* 5MC@k7rՏE~t>!4hb[?ȨD)u{(hشh]ײ{nGVOk2 y?#ؙ'Fd8'Muyќ2 *1sì!104L>ۤb#d:E]&"-Ůǿ4 BZe(ʽ 9K% Fn/ f38-̶7IU/x #cAy2@trCT8qo-AdBp,5~p8D"EkQb4 ~Jl}LTc_jzZ+لcx6Y{ۘ!w(SV©6E }7(U+e|Y3GU'~꓀`Ct,yxQX: Pre$5"a.SQ܆'9[l-gN doC54z&]lSR&cXAt (t̩26 ltr,Rr-pB:" Jhϩt1NY+K_>F7+$֌3il2Sw*)b#+6}(17س29,A+3/cHhR#hUZL <D׍q?|BsXcW(%Hk[Si8٨l?Dqˢ4D$N6M$-;oc[YS[~˧4eRFR}2hRPLs C,SlbDQL䋨K9am)!kBvIgxVS ?=bP8+PJ+ "PSO=Q ؋Ę<ˬY5Fl" -2 a7}YXAȉP ʠu cRҴK3s[߲",ELLŃ!@5t*v'XMe ;7S1cK4~b鍮7)sdi5~G6;7|un?põ˺2EXa &{>H[gKV[,0DQ@i)34bjU,#qy՛[)+A.ڛ"5B u$T`+*JEj MY3D8X4S[ #+if\8iYCӿ5!,FIHB&aT3Uxnzא^;WMilW౏RɟKb_?s3%b~\:P|dYLT SFN3lFi/O}` !X\NG/v-Me;V{YV/<F7#Իz1VA‹Ϣ@>XVwߔY|[B{!]}T(ZU8AJzoCv$2k![GXۅmځ),QA&jmm, ܗ7nq}T⢨] Xc̟bsBS `ҺZHt|d*34~fY\J웖>p|bߚXSr9kjc*lWEMkŅkZ3WKf,s1K5r ҂#j A2͑Nz^GG;$/l^OG>CZھ%޶X=,Į,s5?Xe|/vF3Y Mʊ+^+J?%+~U]LiPJA,˥q$tSUBPM2n`Y)z)3çqPnh85KCEA2=]]->$߾]p o-W''Dx˂5ć 8^ rDD|uꟖ`,O4VWyӝEpTڰ_0龒m0/Jb#N99EҠVe6OScwyy>:Tf;?dG̝:k5}ȢIgb0;s&@ryRq= 1=D#/[Fa/}o;E . [ JL(c>q;i ,44m*Mˮx_YY_jK~K벖eJ^ayQ,)yz(-hֹ#;$1Whg? [9r<3>"d Cg@ )R&IGeťa] :ӇsХP%vNMNwLhK&O8>ErG^ؼyW ^/s`,-TΓua7Ʒ2=wmgv]N'͏i[c(L1,K]gS8+kO\1i`/FkT_EL~Pߡ Ac(0ɦI|˾SO50 ^; da%T0!͓p3RIwGw^xI6y67]yN Mo{y*oϙq7v'K9{{b`ҁjP^LJ*ؔ̓hj@ \+~(I0؋WF)ӛva:m66, O0U,J*d5Kc!!X9X"qCEw&&\US@ H~DyȽgS?4 EҊ@PfA/,@_mHz /<-Yuc5ٝx_e|$;۩: kÚL9)6DCvpЉ1A8Lˋ%}ݦ1n(Կg.7dί4ˍW8~SC[T&/}L IS